home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / mail / listserv / listproc6.0c.940712.0.sh.Z / listproc6.0c.940712.0.sh
Encoding:
Linux/UNIX/POSIX Shell Script  |  1994-08-28  |  1.3 MB  |  40,129 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. #! /bin/sh
  2. # Copyright (c) 1991-1993, Anastasios C. Kotsikonas
  3. #
  4. touch setup systest upgrade_to_6.0c; chmod 700 setup systest upgrade_to_6.0c
  5. #!/bin/sh
  6. # Determine how echo suppresses new-line
  7. echo "a\c" > /tmp/echo
  8. if [ "`grep c /tmp/echo`" = "a\c" ]; then
  9.   n='-n'
  10.   c=''
  11. else
  12.   n=''
  13.   c='\c'
  14. fi
  15. rm /tmp/echo
  16.  
  17. echo
  18. echo \    \    \     ListProcessor 6.0
  19. echo \    \    \     -----------------
  20. echo
  21. if [ -d osrc -o -d ohelp -o -d oarchives -o -f oconfig -o -f o.ignored \
  22.      -o -f oowners -o -f ounwanted.hosts -o -f opriv.hosts -o -d outil \
  23.      -o -f owelcome.live ]; then
  24.   echo Old system image found:
  25.   echo
  26.   ls -CFd o[a-w\.]*
  27.   echo
  28.   echo The current system will be moved to files/dirs starting with \'o\'
  29.   echo as shown above and confirmation is required to remove that old image.
  30.   echo $n "Proceed [y]? $c"
  31.   read x
  32.   if [ "$x" = "n" -o "$x" = "N" ]; then
  33.     exit 0
  34.   fi
  35. fi
  36. if [ -d src ]; then
  37.   echo WARNING: Moving src/ to osrc/
  38.   rm -rf osrc
  39.   rmdir osrc > /dev/null 2>&1
  40.   mv src osrc
  41. fi
  42. if [ ! -d src ]; then
  43.   mkdir src
  44. fi
  45. if [ ! -d src/ansi ]; then
  46.   mkdir src/ansi
  47. fi
  48. if [ ! -d src/nonansi ]; then
  49.   mkdir src/nonansi
  50. fi
  51. if [ ! -d gateway ]; then
  52.   mkdir gateway
  53. fi
  54. if [ ! -d doc ]; then
  55.   mkdir doc
  56. fi
  57. if [ -d help ]; then
  58.   echo WARNING: Moving help/ to ohelp/
  59.   rm -rf ohelp
  60.   rmdir ohelp > /dev/null 2>&1
  61.   mv help ohelp
  62. fi
  63. mkdir help
  64. if [ -d util ]; then
  65.   echo WARNING: Moving util/ to outil/
  66.   rm -rf outil
  67.   rmdir outil > /dev/null 2>&1
  68.   mv util outil
  69. fi
  70. mkdir util
  71. if [ -d archives ]; then
  72.   echo WARNING: Moving archives/ to oarchives/
  73.   rm -rf oarchives
  74.   rmdir oarchives > /dev/null 2>&1
  75.   mv archives oarchives
  76. fi
  77. mkdir archives
  78. mkdir archives/listproc
  79. mkdir archives/listproc/example.dat
  80. mkdir archives/pub
  81. mkdir archives/pub/unix
  82. mkdir archives/pub/private
  83. mkdir archives/unix
  84. mkdir archives/ilp
  85. if [ -f config ]; then
  86.   echo WARNING: Moving config to oconfig
  87.   mv config oconfig
  88. fi
  89. if [ -f owners ]; then
  90.   echo WARNING: Moving owners to oowners
  91.   mv owners oowners
  92. fi
  93. if [ -f .ignored ]; then
  94.   echo WARNING: Moving .ignored to o.ignored
  95.   mv .ignored o.ignored
  96. fi
  97. if [ -f unwanted.hosts ]; then
  98.   echo WARNING: Moving unwanted.hosts to ounwanted.hosts
  99.   mv unwanted.hosts ounwanted.hosts
  100. fi
  101. if [ -f welcome.live ]; then
  102.   echo WARNING: Moving welcome.live to owelcome.live
  103.   mv welcome.live owelcome.live
  104. fi
  105. echo x - src/README
  106. sed 's/^X//' >src/README <<'*-*-END-of-src/README-*-*'
  107. X
  108. X
  109. X                         LISTPROCESSOR SYSTEM
  110. X                         --------------------
  111. X
  112. X           Copyright (c) 1991-93, Anastasios C. Kotsikonas
  113. X
  114. X                           tasos@cs.bu.edu
  115. X                 July 1 1993
  116. X
  117. XDESCRIPTION:
  118. X     This is a system that implements various mailing lists  with
  119. X     one  list manager. It is automated, and obliterates the need
  120. X     for user intervention and maintenance of multiple aliases of
  121. X     the  form  "list,  list-owner,  list-request", etc. There is
  122. X     support  provided  for  public  and   private   hierarchical
  123. X     archives,  moderated  and  non-moderated  lists, peer lists,
  124. X     peer servers, private lists, address aliasing, news  connec-
  125. X     tions  and gateways, mail queueing, digests, list ownership,
  126. X     owner preferences, crash recovery, batch processing,  confi-
  127. X     gurable headers, regular expressions, archive searching, and
  128. X     live user connections via TCP/IP.
  129. X
  130. XCOPYING: You may distribute the software freely, but you may not include
  131. Xany part of the code in a commercial application whatsoever, directly or by
  132. Ximplication. Modified code may NOT be distributed.
  133. X
  134. XAGREEMENT: This software can be used and distributed freely only as a
  135. Xwhole and not in parts, as long as you do not remove or alter the author
  136. Xand copyright notices in the file defs.h; this notices are #define'd in
  137. Xthe symbols VERSION and COPYRIGHT. Although you may alter the code
  138. Xprovided for your personal use, you may not alter the functions
  139. Xcreate_header(), create_multi_recipient_header() and main() in list.c,
  140. Xlistproc.c and serverd.c (where applicable), and you may not redistribute
  141. Xany changes you may have made. No part of the source code bearing a
  142. Xcopyright notice can be included in commercial software systems without
  143. Xwritten permission by the author.
  144. XBy using this software you are bound by this agreement. 
  145. XThis software comes with no warranties and cannot be sold for profit.
  146. XThe AGREEMENT and COPYRIGHT notices should be included in all source
  147. Xfiles when distributing this software.
  148. XCOPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  149. XUse, duplication or disclosure by the Federal Government is subject to the
  150. Xrestrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  151. Xfor Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  152. X
  153. XUPDATES: All updates can be obtained from cs-ftp.bu.edu (128.197.13.20) via
  154. Xanonymous ftp, in the directory pub/listproc. If you downloaded this version
  155. Xfrom another ftp site, please keep an eye on cs-ftp.bu.edu. Bug fixes will
  156. Xbe posted periodically over there, and no notifications will be posted to
  157. Xnews; you should check the directory periodically.
  158. X
  159. XCOMPILER: The programs are written to be ANSI C compliant (almost); if your
  160. Xcompiler cannot handle them, I suggest you also download unproto.tar.Z
  161. Xfrom cs-ftp.bu.edu; cd pub/unproto; this is a nice set of programs that will
  162. Xconvert ANSI-isms to old style C -- please send any questions about unproto
  163. Xto its author, not me. In this case, follow the instructions in the Makefile
  164. Xin the src directory for adjustments to be able to use this package.
  165. XFor those compilers that die when they see a contol-L in the source code, I
  166. Xhave written a C program that "cleans" source files; it is called clean.c and
  167. Xcan be found in pub/utils as well; compile as follows:
  168. X        % cc -Dunix clean.c -o clean
  169. XThe compiler should support symbol names longer than 8 characters. Also consult
  170. Xthe Makefile, as well as the PORT SPECIFIC section in ../doc/server.1
  171. X
  172. XLINKING: If you are using the interactive part of ListProcessor and your
  173. Xsetup uses a name server, you may wish to link with libraries that provide
  174. XDNS support (for example, on SYSV R4 compile with -lsockdns instead of
  175. X-lsocket).
  176. X
  177. XPREPROCESSOR: Strings are defined using both ANSI C specifications and
  178. Xnon-ANSI standards, so that unproto will work correctly (unproto 2.0 does not
  179. Xhandle ANSI string concatenations). Which ones are used during compilation 
  180. Xdepends whether the macro __STDC__ is defined by the compiler/preprocessor.
  181. XNote: the script 'stds' is now rarely needed and can be obtained from cs-ftp.bu.edu
  182. Xin the directory pub/listproc/utils.
  183. X
  184. XSOURCE CODE MODIFICATIONS: If you modify the code to work around problems
  185. Xwith your operating system, or enhance the system, please send me diff's
  186. Xto be incorporated in the next release.
  187. X
  188. XTCP/IP SUPPORT: The 'system' mailmethod and the live ListProcessor require
  189. Xsupport for Berkeley sockets and internet support. The system defines the macro
  190. XTCP_IP in defs.h. Remove this definition if your host does not support sockets,
  191. Xetc. Failure to do so will lead to compiler errors.
  192. X
  193. XSEMAPHORE/SIGNAL SUPPORT: The interactive part of the system depends on
  194. Xsemaphore support. If your host does not support semaphores, undefine the
  195. Xsymbol GO_INTERACTIVE in defs.h; this symbol is automatically undefined if
  196. XTCP_IP is not defined, or the SIGCLD/SIGCHLD, SIGUSR1 and SIGUSR2 signals are
  197. Xnot present. The system uses the POSIX waitpid() function which may not be
  198. Xavailable on your system (like Sequent for example). You may use wait3()
  199. Xinstead; see serverd.c, sighandle(). If you use wait3() and its first argument
  200. Xwhould be a union, then compile with -DWAIT3_NEEDS_UNION (integer is used by
  201. Xdefault).
  202. X
  203. XSPECIAL HEADER FILES: Platforms that have the <sys/select.h>, <ulimit.h>
  204. Xand/or <setjmp.h> header files should use -DHAVE_SELECT_H -DHAVE_ULIMIT_H 
  205. Xand -DHAVE_SETJMP_H when compiling.
  206. X
  207. XSIGNALS: Various UNIX versions deal with signals in a number of ways.
  208. XIf your UNIX is strict SYSVR4 compile with -Dsvr4 -- SYSVR4 uses sighold() and
  209. Xsigrelse(); if it is SYSVR3 compile with -Dsvr3 -- the same functions are
  210. Xdefined; if it is strict BSD based compile with -Dbsd -- BSD uses
  211. Xsigblock() and sigsetmask(). If your system does not define either of these
  212. Xsets of routines or is not a strict implementation of the above, do not
  213. Xuse the above flags and certain signals will be ignored at certain times
  214. Xdue to an old- bug with system(). In defs.h certain ports are given
  215. Xpredefined flavors.
  216. X
  217. XNON-BLOCKING I/O: The system employs a timeout mechanism that works
  218. Xonly with the 'system' mailmethod, provided that the host supports
  219. Xnon-blocking I/O; if it does not, undefine the symbol NONBLOCKING_IO
  220. Xin defs.h (defined by default).
  221. X
  222. XLOCKS: The system relies heavily on locks; however, a number of systems
  223. Xdo not support locking across NFS mounted file systems, or do not support
  224. Xlocks at all. If you are experiencing locking problems, define the symbol
  225. XNO_LOCKS in defs.h (or compile with -DNO_LOCKS) and pray, or move the system
  226. Xto a local file system. The following ports have NO_LOCKS automatically
  227. Xdefined: Minix, Ultrix, NeXT, Apollo, Xenix, Convex.
  228. X
  229. XSYSLOG: You may use syslog(3) for reporting if you compile with
  230. X-DSYSLOG=facility.
  231. X
  232. XUSING ANOTHER HOST TO SEND MAIL: By default, the 'system' mailmethod connects
  233. Xto "localhost" for mail delivery; you may use another host by altering the
  234. Xsymbol SENDMAIL_HOST in sysmail.h
  235. X
  236. XSUBSCRIPTION SUSPENSION: The system scans error messages looking for addresses
  237. Xto suspend sending mail to, and it allows by default a 7 day grace period. This
  238. Xperiod may be changed by altering list.h or by compiling with
  239. X-DGRACE_PERIOD=time_in_seconds.
  240. X
  241. XErrors-To: lines: If you do not want the system to put Errors-To: lines 
  242. Xcompile with -DNO_ERRORS_TO.
  243. X
  244. XZMAILER and other non-sendmail mailers: If your mailer requires a
  245. X'HELO hostname' or 'HELO ip-address' greeting, then compile with -DZMAILER.
  246. XIf TCP/IP is available, the host's name and IP address are obtained with system
  247. Xcalls. If not, they default to "localhost" and "127.0.0.1" (see defs.h) and
  248. Xthey have to redefined. By default, the hostname is included in the greeting.
  249. XIf the IP address is required, see list.c and listproc.c.
  250. X
  251. XUPGRADING: If you are upgrading from an earlier version, take a look at the
  252. XUPGRADING and PORT SPECIFIC sections in ../doc/server.nr and run the
  253. Xupgrade_to_6.0c shell script.
  254. X
  255. XPORTS: The code has been ported to the following UNIXes:
  256. XSUN, IBM, SGI, DEC, HP, Convex, Stardent, KPC, NeXT, SCO, Apollo, Sequent, Data
  257. XGeneral, i860, i386 (bsd) and OSF. If you are on a different host, try first
  258. Xcompiling with -Dunknown_port.
  259. X
  260. XINSTALLATION DIRECTORY: Change the HOMEDIR symbol in Makefile to be the top
  261. Xlevel directory where this system is installed.
  262. X
  263. XFORUM: You should join our forum at unix-listproc@avs.com where we
  264. Xdiscuss problems and enhancements about this system; send a subscribe request
  265. Xto listproc@avs.com
  266. X
  267. XACKNOWLEDGEMENTS: I would like to thank the following people for their
  268. Xsuggestions and contributions to this system (not all suggestions have been
  269. Xincorporated):
  270. X1) Bob Boyd (rbn@epavax.rtpnc.epa.gov): IRIX port, gateway connections
  271. X   feedback, 5.3 beta testing. [Since Dec. 1992 Bob is no longer at EPA 
  272. X   and I wish him good luck]
  273. X2) Stefan Schroer (Stefan.Schroer@cyber.urz.uni-wuppertal.dbp.de): MINIX port
  274. X   (code not reported since 5.0), help files, original 'get' and 'index'
  275. X   requests.
  276. X3) Scott J. Ellentuch (tuc@stormking.com): IBM R6000 port, enhancements to
  277. X   the farch utility, 5.3&up beta testing, setting up of the unix-listproc
  278. X   forum, endless support on the net -- he is my buddy.
  279. X4) David Warner (warner@austin.onu.edu): IBM R6000 bug fixing, 5.3 beta 
  280. X   testing, tolerance with my obnoxious code -- I owe this gentleman a lot.
  281. X5) Nathan F. Estey (nestey@copper.Denver.Colorado.EDU): 5.4 suggestions.
  282. X6) Aad Nienhuis (aad@sconar.sco.uva.nl) for the catmail utility.
  283. X7) Warren Burstein (warren@itexjct.jct.ac.il): digests, owner moderated lists
  284. X   (listproc sends messages to owner, owner sends back the approved ones --
  285. X   my scheme uses APPROVE and DISCARD requests), significant code rewriting,
  286. X   manager preferences, automatic archiving of messages.
  287. X8) Nicos Kontopoulos (nicos@cs.bu.edu) for a lot of tiny suggestions.
  288. X9) Matthias Klose <doko@cs.tu-berlin.de>, John Neil <neil@dehn.mth.pdx.edu>
  289. X   for the NeXT port.
  290. X10) Ken Mayer (ken@visix.com) for the Precedence: stuff.
  291. X11) Henry Spencer for the pattern matching routines.
  292. X12) Carlos O'Ryan Lira (coryan@mat.puc.cl) for the Apollo port.
  293. X13) Anand V Raman (A.Raman@massey.ac.nz) for modifying 'setup' to rebuild the
  294. X    system under the HOMEDIR definition in Makefile.
  295. X14) Kenneth Lorber (keni@oasys.dt.navy.mil) for providing fio.c and speeding up
  296. X    the system by reducing the number of syscom()'s.
  297. X15) All of those of you who made literally a myriad of small suggestions here
  298. X    and there, and contributed even a single character of code, and especially
  299. X    all of you who let me into your systems to do the ports myself.
  300. X
  301. X            The ListProcessor system includes 158 files:
  302. X
  303. X HOMEDIR/doc:
  304. X   *.nr        -- proformatted man pages
  305. X   catmail.1    -- man page for the catmail utility
  306. X   farch.1    -- man page for the file archiving utility
  307. X   ilp.1    -- man page for the Interactive ListProcessor client
  308. X   list.1    -- man page for the mailing list processing application
  309. X   listproc.1    -- man page for the request processing application
  310. X   queue.1    -- man page for the mail queue processing application
  311. X   server.1    -- man page describing the system
  312. X   serverd.1    -- man page for the system daemon
  313. X   start.1    -- man page for the system's housekeeper
  314. X   README    -- instructions for installing the man pages on your system
  315. X
  316. X HOMEDIR/help:
  317. X   TOPICS    -- index file with topics and corresponding filenames
  318. X   general      -- general help file
  319. X   approve    -- help on the approve request
  320. X   discard    -- help on the discard request
  321. X   information  -- help on the information request
  322. X   lists        -- help on the lists request
  323. X   recipients   -- help on the recipients request
  324. X   set          -- help on the set request
  325. X   statistics   -- help on the statistics request
  326. X   subscribe    -- help on the subscribe request
  327. X   unsubscribe  -- help on the unsubscribe request
  328. X   index    -- help on the index request
  329. X   get        -- help on the get request
  330. X   release    -- help on the release request
  331. X   which    -- help on the which request
  332. X   reports    -- help on the reports request
  333. X   edit        -- help on the edit request
  334. X   put        -- help on the put request
  335. X   live        -- help on how to access the live ListProcessor
  336. X   listproc    -- help on this system
  337. X   fax        -- help on the fax request
  338. X   search    -- help on the search request
  339. X   run        -- help on the run request
  340. X
  341. X HOMEDIR/archives:
  342. X   HOMEDIR/archives/listproc: Master archive:
  343. X     DIR    -- info on files and directories they are located
  344. X     INDEX    -- master index of all archives (listproc, pub, unix)
  345. X     summary-of-requests    -- list of all commands
  346. X     info    -- info on this archive
  347. X     HOMEDIR/archives/listproc/example.dat:
  348. X       example.dat1    -- part 1 of file example.dat in archive listproc
  349. X       example.dat2    -- part 2 of file example.dat in archive listproc
  350. X       example.dat3    -- part 3 of file example.dat in archive listproc
  351. X   HOMEDIR/archives/ilp: Source files for the ILP client:
  352. X     DIR    -- info on files in this subdirectory
  353. X     INDEX    -- index of all archives in this archive
  354. X     ilp.c    -- the ILP client
  355. X     ilp.h    -- specific definitions for ilp.h
  356. X     ilpp.h    -- definition of ILP Protocol
  357. X     ilp.1    -- (as before)
  358. X     ilp.nr    -- (as before)
  359. X     makefile    -- makefile to build the ILP client
  360. X   HOMEDIR/archives/pub: Subarchive of listproc:
  361. X     DIR    -- info on files and directories they are located
  362. X     INDEX    -- index of all archives in this archive
  363. X     info    -- info on this archive
  364. X   HOMEDIR/archives/unix: Subarchive of listproc:
  365. X     DIR    -- info on files and directories they are located
  366. X     INDEX    -- index of all archives in this archive
  367. X     info    -- info on this archive
  368. X   HOMEDIR/archives/pub/unix: Subarchive of pub (duplicate name example):
  369. X     DIR    -- info on files and directories they are located
  370. X     INDEX    -- index of files in this archive
  371. X     info    -- info on this archive
  372. X   HOMEDIR/archives/pub/private: Subarchive of pub; example private archive
  373. X     DIR    -- info on files and directories they are located
  374. X     INDEX    -- index of files in this archive
  375. X     info    -- info on this archive
  376. X
  377. X HOMEDIR/src:
  378. X   REGISTRATION    -- registration form for using this software
  379. X   README    -- this file
  380. X   global.h    -- global variables definitions
  381. X   struct.h    -- defines the server structure
  382. X   defs.h    -- general definitions
  383. X   tlock.c    -- tests for locks, i.e. whether any server programs are running
  384. X             on another file system via NFS
  385. X   list.h    -- specific definitions for list.c
  386. X   list.c    -- the list's server
  387. X   listproc.h    -- specific definitions for listproc.c
  388. X   listproc.c    -- server for individual requests
  389. X   pqueue.h    -- specific definitions for pqueue.c
  390. X   pqueue.c    -- processes the mail queue
  391. X   serverd.h    -- specific definitions for serverd.c
  392. X   serverd.c    -- parent program that spawns list or listproc
  393. X   start.h    -- specific definitions for start.c
  394. X   start.c    -- does housekeeping before spawning serverd, makes sure that
  395. X           files exist, kills any running server processes, etc
  396. X   sysmail.h    -- specific definitions for sysmail.c
  397. X   sysmail.c    -- system mailmethod routines
  398. X   catmail.h    -- specific definitions for catmail.c
  399. X   catmail.c    -- append incoming mail to the appropriate file
  400. X   signals.c    -- signal processing routines
  401. X   sender.c    -- sender address manipulation routines
  402. X   misc.c    -- general purpose routines
  403. X   farch.c    -- utility for easy archiving of files
  404. X   next.h    -- specific definitions for NeXT hosts
  405. X   sem.c    -- semaphore definitions for serverd's interactive part
  406. X   rev.c    -- source to BSD 'rev'
  407. X   ilpp.h    -- Interactive ListProcessor Protocol definition
  408. X   ilp.h    -- specific definitions for ilp.c
  409. X   ilp.c    -- client application to connect to an interactive system
  410. X   silp.c    -- system ilp used by ListProcessor to connect to remote servers
  411. X   regex.c    -- fornt end to pattern matching routines
  412. X   regerror.c    -- pattern matching routines -- Henry Spencer
  413. X   regexp.c    -- pattern matching routines -- Henry Spencer
  414. X   regexp.h    -- pattern matching routines -- Henry Spencer
  415. X   regmagic.h    -- pattern matching routines -- Henry Spencer
  416. X   regsub.c    -- pattern matching routines -- Henry Spencer
  417. X   fwin.c    -- utility that returns subsets of files
  418. X   fio.c    -- simple system calls submitted by keni@oasys.dt.navy.mil
  419. X   strftime.c    -- UC Berkeley public domain version of this function
  420. X   semset.c    -- utility to check/set a semaphore's value
  421. X   Makefile    -- to build your own server
  422. X
  423. X HOMEDIR/src/ansi:
  424. X   *.h        -- specific ANSI string definitions for various programs
  425. X
  426. X HOMEDIR/src/nonansi:
  427. X   *.h        -- specific non-ANSI string definitions for various programs
  428. X
  429. X HOMEDIR/gateway:
  430. X   gateway.c    -- gateway for connecting your host to another on Internet
  431. X   gateway.h    -- specific definitions for gateway.c
  432. X   ilpp.h    -- definition of the interactive ListProcessor Protocol
  433. X   README    -- how to install and use the gateway
  434. X   Makefile    -- how to build the gateway
  435. X
  436. X HOMEDIR/util:
  437. X   combine.c    -- user utility to automatically combine archive files
  438. X           received in multiple mail messages
  439. X   expn.c    -- check if address is reachable
  440. X   check_addr    -- script to check the validity of an incoming address
  441. X   mmdfcatmail.c -- utility to use before catmail if using an MMDF mailer
  442. X   which.sh    -- UCB "which" source
  443. X   use_From:_address.sh -- program+script to use the From: address instead of
  444. X               the "From " for identification
  445. X
  446. X HOMEDIR:
  447. X   makefile    -- to build your system
  448. X   ILPP        -- description of the ILP protocol
  449. X   setup        -- a script to be run before starting for the first time
  450. X   systest    -- script that analyzes your system
  451. X   queued    -- daemon controlling the processing of the mail queue
  452. X   peer        -- script to add a peer list
  453. X   news        -- script to add a news group to a list
  454. X   redux        -- script that reduces the size of mbox by removing unnecessary
  455. X                   fields from the header of each message
  456. X   ulock        -- in conjunction with the 'flocks' file, this utility
  457. X                   removes all locked files (unlocks them)
  458. X   flocks       -- script to remove locked files
  459. X   .awk        -- awk program used for the 'statistics' and 'recipients'
  460. X          ListProcessor requests
  461. X   .stats    -- shell script used for the 'statistics' ListProcessor request
  462. X   .grep    -- shell program used for the 'statistics' ListProcessor request
  463. X   .ignored    -- a list of email addresses whose messages are ignored
  464. X   owners    -- a list of all list owner addresses
  465. X   unwanted.hosts -- hosts not allowed to connect to ILP
  466. X   upgrade_to_6.0c -- upgrade script
  467. X   welcome.live    -- welcome message upon live log in
  468. X   README    -- general guidelines for first time users
  469. X   FAQ        -- most frequently asked questions
  470. X   WHATS_NEW    -- what's with this version
  471. X   config    -- the system's configuration file
  472. X
  473. X
  474. X               |-->-----------> START
  475. X               |                  |
  476. X               |                  |
  477. X               ^          (spawns-and-dies)
  478. X               |                  |
  479. X               |                  |
  480. X               |--<--restart--- SERVERD <--shutdown-<--|
  481. X                                  /\                   r
  482. X                                 /  \                  e
  483. X                                /    \                 s
  484. X                    (spawns either one as necessary)   t       
  485. X                              /        \               a
  486. X                             /          \              r
  487. X                           LIST        LISTPROC --->---t
  488. X
  489. X
  490. XThe diagram shows that 'start' spawns 'serverd' and then dies, and that
  491. X'listproc' may request 'serverd' to die (shutdown) or request that the
  492. Xsystem is restarted, in which case 'serverd' spawns 'start' and dies.
  493. X
  494. XEnjoy!
  495. X
  496. XRevision history:
  497. X
  498. XVersion      Date     Status    Comments
  499. X------------------------------------------------------------------------------
  500. X 3.45      12/20/90  Outdated * First public version; bugs with listproc
  501. X 3.67      01/03/91  Outdated   Bugs fixed
  502. X 3.68      01/04/91  Outdated * v3.67 + tlock utility
  503. X 4.0       04/09/91  Exprmntl   v3.68 + STATISTICS listproc command
  504. X 4.1       04/16/91  Outdated   v4.0 + redux utility
  505. X 4.2       05/02/91  Outdated   v4.1 w/ optimized source code, better doc.
  506. X 4.21      05/03/91  Outdated   v4.2 w/ redux which was left out by mistake
  507. X 4.3       05/03/91  Outdated * v4.21 w/ better mailer-daemon msg handling
  508. X 4.4       05/22/91  Exprmntl   v4.3 w/ enhanced tlock,control,start,listproc
  509. X 4.5       06/12/91  Exprmntl   v4.3 w/ enhanced listproc
  510. X 5.0       07/17/91  Outdated * v4.4 + support for multiple lists
  511. X 5.1       08/27/91  Outdated   v5.0 + bug fixes, enhanced listproc
  512. X 5.1 Rev I 10/03/91  Outdated   v5.0 + more bug fixes
  513. X 5.2       10/08/91  Outdated * v5.1 + archives, GET, INDEX requests,
  514. X                        farch utility, moderated lists,
  515. X                       disabled listproc commands on a per list
  516. X                       basis, link with peer lists and news
  517. X                       feeds
  518. X 5.2 Rev A 10/10/91  Outdated   v5.2 + bug fixes
  519. X 5.21      10/15/91  Exprmntl   v5.2A + multiple recipients in one message
  520. X 5.3 beta  10/31/91  Exprmntl   v5.21 + system mailmethod, bug fixes
  521. X 5.3        12/05/91  Outdated   v5.21 + bug fixes, universal system mailmethod,
  522. X                    multiple recipients in one message,
  523. X                    support for blanks in email addresses,
  524. X                    user-set limit on size of messages,
  525. X                    RFC 821 compliant SMTP implementation,
  526. X                    extensive mail loop detection mechanism,
  527. X                    new scripts (stds, reformat), enhanced
  528. X                    GET request, and more.
  529. X 5.31       12/09/91  PstdNews * v5.3 + mail queueing capability/subsystem +
  530. X                       RELEASE request
  531. X 5.4 beta  12/16/91  Exprmntl   v5.31 + crash recovery mechanism, manager
  532. X                    approved subscriptions (private lists),
  533. X                    multiple lines of text for describing
  534. X                    archived files, batch processing,
  535. X                    WHICH request, automatic use of
  536. X                    unproto in the Makefile, private
  537. X                    archives, list owners with restricted
  538. X                    system privileges, email aliasing
  539. X                    for requests, SYSTEM/REPORTS/PUT/EDIT
  540. X                    list administration requests, automatic
  541. X                    archiving of distributed messages only,
  542. X                    enhanced INDEX/GET requests, same
  543. X                    archive names allowed on different
  544. X                    levels of the hierarchy (path spec. to
  545. X                    an archive)
  546. X 5.4       02/05/92  Outdated   v5.31 + v5.4 beta
  547. X 5.41       03/05/92  PstdNews * v5.4 + catmail (system is now more secure), bug
  548. X                    fixes, owner preferences
  549. X 5.5 beta  04/08/92  Exprmntl   v5.41 + two ways for moderating lists by owners
  550. X                    (+ APPROVE/DISCARD list administration
  551. X                    requests), enhanced farch, fix to GET
  552. X                    request, list digests, optional
  553. X                    Comment: line, manager preferences,
  554. X                    enhanced help system, GET/INDEX 
  555. X                    requests now report file sizes, new
  556. X                    config options ignore_invalid_requests
  557. X                    and relaxed_syntax, EXECUTE request
  558. X 5.5       05/18/92  Outdated   v5.5 beta + NeXT port
  559. X 6.0beta   01/19/93  Exprmntl    v5.5 +    interactive system, ULISTPROCESSOR_UMASK
  560. X                    env var, Precedence:, configurable
  561. X                    headers, regular expressions, auto
  562. X                    archiving of lists' messages, enhanced
  563. X                    farch, ability to execute  commands
  564. X                    on a per list basis, ability to
  565. X                    continue commands in the config file on
  566. X                    multiple lines, HP, Apollo, Sequent &
  567. X                    DG ports, interception of requests sent
  568. X                    to a list, list defaults, CONCEAL
  569. X                    attribute, user settable subscription
  570. X                    addresses, various user utilities,
  571. X                    gateway client, screening and analysis
  572. X                    of error messages, support for syslog,
  573. X                    auto splitting of outgoing files, FAX
  574. X                    request
  575. X
  576. X 6.0       04/01/93  Outdated   v6.0beta + ports + bug fixes + SEARCH request
  577. X 6.0a       07/20/93  Outdated   v6.0 +  VIEW requests server/client abort
  578. X                    operation, more bug fixes, true
  579. X                    concurrency
  580. X 6.0b       09/13/93  Outdated * v6.0a + tons of bug fixes, better mail loop
  581. X                    detection
  582. X 6.0c       11/30/93  Released    v6.0b +    ability not to compress archived files,
  583. X                    ULISTPROC_ARCHIVES_UMASK env var, bug
  584. X                    fixes
  585. X
  586. X*Source for these versions has been posted to news.
  587. *-*-END-of-src/README-*-*
  588. echo x - src/REGISTRATION
  589. sed 's/^X//' >src/REGISTRATION <<'*-*-END-of-src/REGISTRATION-*-*'
  590. X
  591. X              LISTPROCESSOR SYSTEM
  592. X              --------------------
  593. X
  594. X              Copy Registration
  595. X
  596. X               tasos@cs.bu.edu
  597. X
  598. XKeep an eye on the anonymous ftp site cs-ftp.bu.edu (128.197.13.20) in the directory
  599. Xpub for any updates.
  600. X
  601. XThe list unix-listproc@avs.com served by listproc@avs.com
  602. Xis a forum about this system.
  603. X
  604. XIf you use this software and have not filled out a registration form before,
  605. Xplease email me the following information:
  606. X
  607. XName:
  608. XEmail address:
  609. XOrganization:
  610. XAddress:
  611. XPhone:
  612. XType of computer system:
  613. XVersion of server using (% list -v):
  614. XComments:
  615. *-*-END-of-src/REGISTRATION-*-*
  616. echo x - src/Makefile
  617. sed 's/^X//' >src/Makefile <<'*-*-END-of-src/Makefile-*-*'
  618. X# Makefile for ListProcessor 6.0
  619. X#
  620. X# The programs are written to be fully ANSI C compliant. The symbol CC below
  621. X# may have to be redefined if an ANSI C compiler is to be used. This ANSI
  622. X# compiler should define the marco __STDC__
  623. X#
  624. X# Suggestions:
  625. X# SGI: IRIX 4: cc -ansi -D_POSIX_SOURCE, or cc -D__STDC__ -D_POSIX_SOURCE
  626. X# SGI: IRIX 5: cc -D_BSD_SOURCE -Dsvr4
  627. X# SUN SUNOS 4.x: Use /usr/lang/acc when available; compile with
  628. X#   -DSETPGRP_NEEDS_ARGS
  629. X# SUN Solaris 5.2+: Compile with -Dsvr4; link with -lsocket -lnsl
  630. X# NeXT: Compile with -D__NeXT__ if the compiler does not define this symbol,
  631. X#   and -I/usr/include/bsd -I/usr/include/bsd/sys; also with
  632. X#   -DSETPGRP_NEEDS_ARGS
  633. X# HP-UX: cc -Aa -D_HPUX_SOURCE
  634. X# IBM: xlc -D_ALL_SOURCE -qnoro -DSETPGRP_NEEDS_ARGS
  635. X# SYSVR4 Systems: link with -lnsl and -lsocket or -lsockdns if you are using
  636. X#   a name server
  637. X# SCO: Compile with -Dsco -I/usr/include/netinet
  638. X# Apollo: Do not compile with -A ansi; if you need to, also compile with
  639. X#   -Dapollo
  640. X# Sequent: gcc -fwritable-strings
  641. X# Data General: gcc -fwritable-strings
  642. X# Stardent/KPC Titan: cc (do not use -43)
  643. X# OSF: cc -std1 -DSETPGRP_NEEDS_ARGS
  644. X# i386: cc -fwritable-strings
  645. X# i860: cc
  646. X# NetBSD: cc -DNetBSD
  647. X#
  648. X# To use the unproto package during compilation, uncomment the symbols
  649. X# SRC and COMP below, and comment out the default ones.
  650. X#
  651. X# Also read the README file in this directory as well as ../doc/server.nr
  652. X# (the PORT SPECIFIC section)
  653. X#
  654. X# On some systems that do not use BSD-style sockets and signals (SIGIO)
  655. X# you need to link with a BSD library that defines them, although this is not
  656. X# critical. See the man page for ilp(1) for more details.
  657. X#
  658. X# Examples:
  659. X# AIX: Link with -lbsd
  660. X# SCO: Link with -lsocket
  661. X#
  662. X# SIGNALS: Various UNIX versions deal with signals in a number of ways.
  663. X# If your UNIX is strict SYSVR4 compile with -Dsvr4 -- SYSVR4 uses sighold()
  664. X# and sigrelse(); if it is SYSVR3 compile with -Dsvr3 -- the same functions are
  665. X# defined; if it is strict BSD based compile with -Dbsd -- BSD uses
  666. X# sigblock() and sigsetmask(). If your system does not define either of these
  667. X# sets of routines or is not a strict implementation of the above, do not
  668. X# use the above flags and certain signals will be ignored at certain times.
  669. X# In defs.h certain ports are given predefined flavors.
  670. X#
  671. X# LINKING: If you are using the interactive part of ListProcessor and your
  672. X# setup uses a name server, you may wish to link with libraries that provide
  673. X# DNS support.
  674. X#
  675. X# Optional compiler flags that can be used:
  676. X#   -DHAVE_SELECT_H: if your system provides the <sys/select.h> include file
  677. X#   -DHAVE_ULIMIT_H: if your system provides the <ulimit.h> include file
  678. X#   -DHAVE_SETJMP_H: if your system provides the <setjmp.h> include file
  679. X#   -DHAVE_TZFILE_H: if your system provides the <tzfile.h> include file
  680. X#   -DSYSLOG=facility: if you want to use syslog(3) for reports
  681. X#   -DNO_LOCKS: if you do not want file locking
  682. X#   -DNO_ABORT_OP: if you do not want abort capability (^C) with live
  683. X#    connections (suggested if compiler errors)
  684. X#   -DNO_TCP_IP: if TCP/IP is not installed or available
  685. X#   -DNO_ERRORS_TO: if you do not want Errors-To: lines in messages
  686. X#   -DDONT_GO_INTERACTIVE: if the system should not go live (see below)
  687. X#   -DERROR_MAIL_ANALYSIS=level: if you want the system to analyze 
  688. X#    mailer-daemon error messages and take automatic action; default is
  689. X#    off; level ranges from 1 (very conservative) to 9 (complete analysis +
  690. X#    guess-attempts); see also GRACE_PERIOD below -- this option is still
  691. X#    under development
  692. X#   -DZMAILER: if you are using Zmailer or any other non-sendmail mailer that
  693. X#    requires 'HELO hostname' to start the SMTP transaction; see also below
  694. X#   -DLIST_CHECKING_FOR_REQUESTS: if you want to screen out requests sent to
  695. X#    lists but allow ones that do not refer to local or remote lists
  696. X#   -DLIST_ALIAS_IN_SUBJECT: if you want each subject line to contain the
  697. X#    list's alias and the current message number
  698. X#   -DNEED_DATE: if you need a Date: header line and your sendmail does not
  699. X#    put one
  700. X#   -DWAIT3_NEEDS_UNION: if using wait3() and its first argument is a union
  701. X#   -DSETPGRP_NEEDS_ARGS: if your setpgrp(2) takes arguments
  702. X#   -DNEED_VSPRINTF: if your system does not provide vsprintf()
  703. X#   -DMAX_LISTS=lists+1: number of lists defined plus one; default is 11
  704. X#   -DUCB_MAIL=\"path\": path to UCB mail program; default is /usr/ucb/mail
  705. X#   -DMAX_LINE=size: internal character buffer length; default is 1024
  706. X#   -DMAX_CONNECTIONS=xxx: define the maximum number of live connections over
  707. X#    TCP/IP; default is 5
  708. X#   -DMAX_EMAILS=num: define the number of messages to send before sleeping
  709. X#    to give time to sendmail to catch up; default is 10
  710. X#   -DSHELL_CHAR_LIMIT=limit: define the maximum number of characters the
  711. X#    shell will accept in the command line; default is 2048; used only
  712. X#    with other-than-system mailmethods
  713. X#   -DUSE_CARRIAGE_RETURN_LINEFEED: if using the system mailmethod and your
  714. X#    SMTP protocol requires each line to be terminated by \r\n; default is
  715. X#    \n
  716. X#   -DBUFFSIZ=size: define the socket buffer size for live connections; default
  717. X#    is 8192
  718. X#   -DILP_PORT=port: define another port for live connections if you do not
  719. X#    have access to /etc/services
  720. X#   -DINEWS=\"path\": path to the inews program for posting articles to news
  721. X#    groups; default is /usr/lib/news/inews
  722. X#   -Dbsd: if your host has a BSD flavor; default is defined in defs.h
  723. X#   -Dsvr3: if your host has a SYSV R3 flavor; default is defined in defs.h
  724. X#   -Dsvr4: if your host has a SYSV R4 flavor; default is defined in defs.h
  725. X#   -Dunknown_port: if the system has not been ported to your host; should
  726. X#    use one of the above system types (bsd, svr3, svr4)
  727. X#   -fwritable-strings: specific to gcc; must be used with gcc
  728. X#
  729. X# Symbols automatically defined for various hosts (depending on the host):
  730. X#   TCP_IP: defined if NO_TCP_IP is undefined
  731. X#   GO_INTERACTIVE: defined if TCP_IP and SIGCLD (SIGCHLD), SIGUSR1 and SIGUSR2
  732. X#    are defined, and DONT_GO_INTERACTIVE is not requested; requires host
  733. X#    support for either waitpid() or wait3(), and semaphores
  734. X#   NO_LOCKS: defined when a system exhibits locking problems over NFS
  735. X#   NONBLOCKING_IO: undefine it if your host does not support it
  736. X#
  737. X# Other symbols that may need tweaking:
  738. X#   HOSTNAME: if TCP_IP is not defined then you need to set your hostname in
  739. X#    defs.h only if you are compiling with -DZMAILER; default is "localhost"
  740. X#   LOCAL_ADDR: same as above; default is 127.0.0.1
  741. X#   SENDMAIL_HOST: default is "localhost"; it defines the host to connect to
  742. X#    when using the 'system' mailmethod to deliver mail (defined in
  743. X#    sysmail.h); compile as follows: -DSENDMAIL_HOST=\"hostname\".
  744. X#   MAILER_DAEMON: email addresses that are given special treatment (defined
  745. X#    in defs.h)
  746. X#   SUSP_SUBJECT: suspicious Subject: lines that get special treatment (defined
  747. X#    in defs.h)
  748. X#   GRACE_PERIOD: time period before subscriptions of erroneous addresses are
  749. X#    suspended; to be used as follows: -DGRACE_PERIOD=time_in_seconds.
  750. X#
  751. X# Always run 'setup' (in the parent directory); do not type 'make' in this
  752. X# directory.
  753. X
  754. X# define your compiler:
  755. XCC        = cc
  756. X
  757. X# define special symbols (system, preprocessor options, etc):
  758. XDEFINES        = -DHAVE_SELECT_H -DHAVE_ULIMIT_H -DHAVE_SETJMP_H \
  759. X          -DHAVE_TZFILE_H -DERROR_MAIL_ANALYSIS=9 \
  760. X          -DUCB_MAIL=\"/bin/mailx\" \
  761. X          -DUSE_CARRIAGE_RETURN_LINEFEED
  762. X
  763. X# define the optimization level
  764. XOPTIMIZATION    = -g
  765. X
  766. X# define where the preprocessor is if using unproto:
  767. X#CPP        = /lib/cpp
  768. X
  769. X# unproto specific definitions -- use either COMP symbol (second is preferred):
  770. X#SRC        = /tmp/$<
  771. X#COMP        = cat $< | unproto > $(SRC); $(CC)
  772. X#COMP        = $(CPP) $(DEFINES) $< | unproto > $(SRC); $(CC)
  773. X
  774. X# default definitions (comment out if using unproto):
  775. XSRC        = $<
  776. XCOMP        = $(CC)
  777. X
  778. X# Reset HOMEDIR to the top level directory the system is installed under:
  779. XHOMEDIR        = /usr/server
  780. X
  781. X# define linking options and libraries
  782. XLDFLAGS        = $(OPTIMIZATION)
  783. XLIBS        =
  784. X
  785. X# Nothing to change below
  786. XSHELL        = /bin/sh
  787. XLD        = $(CC)
  788. XCFLAGS        = -c $(OPTIMIZATION) -I$(PWD) -I$(PWD)/src -I/usr/server/src \
  789. X          -I$(HOMEDIR)/src $(DEFINES)
  790. XCLEAN_TMP    = @if [ $$USE_UNPROTO ]; then \
  791. X            if [ `dirname $(SRC)` = "/tmp" ]; then \
  792. X              rm -f $(SRC); \
  793. X            fi; \
  794. X          else \
  795. X            echo > /dev/null; \
  796. X          fi
  797. X
  798. XARCHIVED        = signals.o sender.o misc.o sysmail.o sem.o silp.o regex.o \
  799. X          regsub.o regerror.o regexp.o fio.o strftime.o
  800. XARCHIVE_LIB     = libserver.a
  801. XTARGETS         = listproc list serverd start tlock farch pqueue catmail ilp \
  802. X          rev fwin semset
  803. X
  804. Xall: $(ARCHIVE_LIB) $(TARGETS)
  805. X
  806. X$(ARCHIVE_LIB): $(ARCHIVED)
  807. X    @rm -f $(ARCHIVE_LIB)
  808. X    ar cr $(ARCHIVE_LIB) $(ARCHIVED)
  809. X    @if [ -f /usr/bin/ranlib -o -f /bin/ranlib ]; then \
  810. X      echo ranlib $(ARCHIVE_LIB); \
  811. X      ranlib $(ARCHIVE_LIB);\
  812. X    else\
  813. X      echo ar ts $(ARCHIVE_LIB); \
  814. X      ar ts $(ARCHIVE_LIB); \
  815. X    fi
  816. X
  817. Xlistproc: listproc.o $(ARCHIVE_LIB)
  818. X    $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS) -lm
  819. X
  820. Xlist: list.o $(ARCHIVE_LIB)
  821. X    $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS) -lm
  822. X
  823. Xserverd: serverd.o $(ARCHIVE_LIB)
  824. X    @rm -f $@
  825. X    $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS) -lm
  826. X
  827. Xstart: start.o $(ARCHIVE_LIB)
  828. X    $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS)
  829. X
  830. Xtlock: tlock.o $(ARCHIVE_LIB)
  831. X    $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS)
  832. X
  833. Xfarch: farch.o $(ARCHIVE_LIB)
  834. X    $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS) -lm
  835. X
  836. Xpqueue: pqueue.o $(ARCHIVE_LIB)
  837. X    $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS)
  838. X
  839. Xcatmail: catmail.o $(ARCHIVE_LIB)
  840. X    $(LD) $(LDFLAGS) $@.o $(ARCHIVE_LIB) -o $@ $(LIBS)
  841. X    @chmod a+rx $@
  842. X    @chmod u+s $@
  843. X
  844. Xilp:    ilp.o
  845. X    $(LD) $(LDFLAGS) $@.o -o $@ $(LIBS) -lm
  846. X    @chmod a+rx $@
  847. X
  848. Xrev:    rev.o
  849. X    $(LD) $(LDFLAGS) $@.o -o $@
  850. X
  851. Xfwin:    fwin.o
  852. X    $(LD) $(LDFLAGS) $@.o -o $@ $(LIBS) -lm
  853. X
  854. Xsemset:    semset.o
  855. X    $(LD) $(LDFLAGS) $@.o -o $@ -lm
  856. X
  857. Xinstall: $(ARCHIVE_LIB) $(TARGETS)
  858. X    @for t in $(TARGETS); do \
  859. X       echo Installing "$$t"; \
  860. X       rm -f $(HOMEDIR)/"$$t"; \
  861. X       if [ -r /bin/ln -o -r /usr/bin/ln -o -r /usr/ucb/ln -o \
  862. X            -r /usr/bsd/ln ]; then \
  863. X         ln -s $(HOMEDIR)/src/"$$t" $(HOMEDIR)/"$$t"; \
  864. X       else \
  865. X         cp "$$t" $(HOMEDIR); \
  866. X       fi; \
  867. X       if [ "`ls -l $$t | awk '{ print $$3 }'`" = "server" ]; then \
  868. X         chmod a+rx $(HOMEDIR)/"$$t"; \
  869. X       fi; \
  870. X    done
  871. X    @(cd $(HOMEDIR); chmod u+s catmail)
  872. X
  873. Xclean:
  874. X    rm -f $(TARGETS) $(ARCHIVE_LIB) *.o
  875. X
  876. X# Hand-generated dependencies
  877. Xlistproc.o:     listproc.c defs.h struct.h global.h listproc.h ansi/listproc.h \
  878. X                nonansi/listproc.h ansi/misc.h nonansi/misc.h ansi/defs.h \
  879. X        nonansi/defs.h
  880. X    @PWD=`pwd`
  881. X    $(COMP) $(CFLAGS) $(SRC)
  882. X    @$(CLEAN_TMP)
  883. X
  884. Xlist.o:         list.c defs.h struct.h global.h list.h ansi/defs.h \
  885. X        nonansi/defs.h
  886. X    @PWD=`pwd`
  887. X    $(COMP) $(CFLAGS) $(SRC)
  888. X    @$(CLEAN_TMP)
  889. X
  890. Xserverd.o:      serverd.c defs.h struct.h global.h serverd.h ansi/serverd.h \
  891. X                nonansi/serverd.h ilpp.h ansi/defs.h \
  892. X        nonansi/defs.h
  893. X    @PWD=`pwd`
  894. X    $(COMP) $(CFLAGS) $(SRC)
  895. X    @$(CLEAN_TMP)
  896. X
  897. Xstart.o:        start.c defs.h struct.h global.h start.h ansi/start.h \
  898. X        nonansi/start.h ansi/misc.h nonansi/misc.h ansi/defs.h \
  899. X        nonansi/defs.h
  900. X    @PWD=`pwd`
  901. X    $(COMP) $(CFLAGS) $(SRC)
  902. X    @$(CLEAN_TMP)
  903. X
  904. Xsender.o:       sender.c defs.h
  905. X    @PWD=`pwd`
  906. X    $(COMP) $(CFLAGS) $(SRC)
  907. X    @$(CLEAN_TMP)
  908. X
  909. Xsignals.o:      signals.c defs.h struct.h
  910. X    @PWD=`pwd`
  911. X    $(COMP) $(CFLAGS) $(SRC)
  912. X    @$(CLEAN_TMP)
  913. X
  914. Xsysmail.o:      sysmail.c defs.h struct.h sysmail.h
  915. X    @PWD=`pwd`
  916. X    $(COMP) $(CFLAGS) $(SRC)
  917. X    @$(CLEAN_TMP)
  918. X
  919. Xmisc.o:         misc.c defs.h struct.h ansi/misc.h nonansi/misc.h ansi/defs.h \
  920. X        nonansi/defs.h
  921. X    @PWD=`pwd`
  922. X    $(COMP) $(CFLAGS) $(SRC)
  923. X    @$(CLEAN_TMP)
  924. X
  925. Xtlock.o:        tlock.c defs.h global.h
  926. X    @PWD=`pwd`
  927. X    $(COMP) $(CFLAGS) $(SRC)
  928. X    @$(CLEAN_TMP)
  929. X
  930. Xfarch.o:        farch.c defs.h struct.h listproc.h ansi/defs.h nonansi/defs.h
  931. X    @PWD=`pwd`
  932. X    $(COMP) $(CFLAGS) $(SRC)
  933. X    @$(CLEAN_TMP)
  934. X
  935. Xpqueue.o:       pqueue.c defs.h struct.h global.h pqueue.h ansi/defs.h \
  936. X        nonansi/defs.h
  937. X    @PWD=`pwd`
  938. X    $(COMP) $(CFLAGS) $(SRC)
  939. X    @$(CLEAN_TMP)
  940. X
  941. Xcatmail.o:    catmail.c defs.h struct.h global.h catmail.h ansi/catmail.h\
  942. X        nonansi/catmail.h
  943. X    @PWD=`pwd`
  944. X    $(COMP) $(CFLAGS) $(SRC)
  945. X    @$(CLEAN_TMP)
  946. X
  947. Xsem.o:        sem.c defs.h ansi/defs.h nonansi/defs.h
  948. X    @PWD=`pwd`
  949. X    $(COMP) $(CFLAGS) $(SRC)
  950. X    @$(CLEAN_TMP)
  951. X
  952. Xilp.o:        ilp.c ilp.h ilpp.h defs.h
  953. X    @PWD=`pwd`
  954. X    $(COMP) $(CFLAGS) $(SRC)
  955. X    @$(CLEAN_TMP)
  956. X
  957. Xsilp.o:        silp.c ilp.h ilpp.h defs.h
  958. X    @PWD=`pwd`
  959. X    $(COMP) $(CFLAGS) $(SRC)
  960. X    @$(CLEAN_TMP)
  961. X
  962. Xregex.o:    regex.c regexp.h
  963. X    @PWD=`pwd`
  964. X    $(COMP) $(CFLAGS) $(SRC)
  965. X    @$(CLEAN_TMP)
  966. X
  967. Xregsub.o:    regsub.c regexp.h regmagic.h
  968. X    @PWD=`pwd`
  969. X    $(COMP) $(CFLAGS) $(SRC)
  970. X    @$(CLEAN_TMP)
  971. X
  972. Xregexp.o:    regexp.c regexp.h regmagic.h
  973. X    @PWD=`pwd`
  974. X    $(COMP) $(CFLAGS) $(SRC)
  975. X    @$(CLEAN_TMP)
  976. X
  977. Xregerror.o:    regerror.c
  978. X    @PWD=`pwd`
  979. X    $(COMP) $(CFLAGS) $(SRC)
  980. X    @$(CLEAN_TMP)
  981. X
  982. Xrev.o:        rev.c
  983. X    @PWD=`pwd`
  984. X    $(COMP) $(CFLAGS) $(SRC)
  985. X    @$(CLEAN_TMP)
  986. X
  987. Xfwin.o:        fwin.c
  988. X    @PWD=`pwd`
  989. X    $(COMP) $(CFLAGS) $(SRC)
  990. X    @$(CLEAN_TMP)
  991. X
  992. Xfio.o:        fio.c
  993. X    @PWD=`pwd`
  994. X    $(COMP) $(CFLAGS) $(SRC)
  995. X    @$(CLEAN_TMP)
  996. X
  997. Xstrftime.o:    strftime.c
  998. X    @PWD=`pwd`
  999. X    $(COMP) $(CFLAGS) $(SRC)
  1000. X    @$(CLEAN_TMP)
  1001. X
  1002. Xsemset.o:    semset.c
  1003. X    @PWD=`pwd`
  1004. X    $(COMP) $(CFLAGS) $(SRC)
  1005. X    @$(CLEAN_TMP)
  1006. X
  1007. *-*-END-of-src/Makefile-*-*
  1008. echo x - src/catmail.h
  1009. sed 's/^X//' >src/catmail.h <<'*-*-END-of-src/catmail.h-*-*'
  1010. X/*
  1011. X  Below are the #define's pertinent to catmail.c (user contributed application).
  1012. X*/
  1013. X
  1014. X#ifdef __STDC__
  1015. X# include "ansi/catmail.h"
  1016. X#else
  1017. X# include "nonansi/catmail.h"
  1018. X#endif
  1019. X#ifdef __NeXT__
  1020. X# include "next.h"
  1021. X#endif
  1022. X
  1023. X#define LOST_MAIL        "lost+found"
  1024. X
  1025. Xint    lfd = 2, lfd2 = 2, lfd3 = 2; /* Set to stderr in case they are closed */
  1026. X                     /* without having been opened before */
  1027. Xint    listid;
  1028. XBOOLEAN tty_echo        = TRUE;
  1029. XBOOLEAN moderated       = FALSE;        /* -m flag off */
  1030. XBOOLEAN reformat        = FALSE;        /* -f flag off */
  1031. XBOOLEAN requests        = FALSE;        /* -r flag off */
  1032. XFILE    *report         = NULL;
  1033. Xint    sid        = -1;
  1034. *-*-END-of-src/catmail.h-*-*
  1035. echo x - src/defs.h
  1036. sed 's/^X//' >src/defs.h <<'*-*-END-of-src/defs.h-*-*'
  1037. X/*
  1038. X  AGREEMENT: This software can be used and distributed freely only as a
  1039. X  whole and not in parts, as long as you do not remove or alter the author
  1040. X  and copyright notices in the file defs.h; this notices are #define'd in
  1041. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  1042. X  provided for your personal use, you may not alter the functions
  1043. X  create_header(), create_multi_recipient_header() and main() in list.c,
  1044. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  1045. X  any changes you may have made. No part of the source code bearing a
  1046. X  copyright notice can be included in commercial software systems without
  1047. X  written permission by the author.
  1048. X  By using this software you are bound by this agreement. 
  1049. X  This software comes with no warranties and cannot be sold for profit.
  1050. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  1051. X  files when distributing this software.
  1052. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  1053. X  Use, duplication or disclosure by the Federal Government is subject to the
  1054. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  1055. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  1056. X
  1057. X  General system definitions.
  1058. X
  1059. X  WARNING: DO NOT CHANGE THE NAME OF THE 'SERVERD', 'LIST' or 'LISTPROC'
  1060. X  PROGRAMS in the system. If you do so, make sure that command line
  1061. X  options are separated by at least a space from the filename.
  1062. X  DO NOT INCLUDE ANY CHARACTERS SUCH AS &, |, <, >. etc.
  1063. X
  1064. X  Preserve any quotes and new lines that appear below; change only path names.
  1065. X
  1066. X  ALWAYS SPECIFY ABSOLUTE PATHS.
  1067. X
  1068. X*/
  1069. X
  1070. X#ifdef _AUX_SOURCE
  1071. X# include <unistd.h>
  1072. X# include <time.h>
  1073. X#endif
  1074. X
  1075. X#ifdef __STDC__
  1076. X# include "ansi/defs.h"
  1077. X#else
  1078. X# include "nonansi/defs.h"
  1079. X#endif
  1080. X
  1081. X#ifndef NO_TCP_IP
  1082. X# define TCP_IP
  1083. X#endif
  1084. X
  1085. X#if defined (TCP_IP) && (defined (SIGCLD) || defined (SIGCHLD)) && \
  1086. X  defined (SIGUSR1) && defined (SIGUSR2)
  1087. X# if !defined (GO_INTERACTIVE) && !defined (DONT_GO_INTERACTIVE)
  1088. X#  define GO_INTERACTIVE 
  1089. X   /* Remove this definition if your host doesn't support semaphores etc. */
  1090. X# endif
  1091. X#endif
  1092. X
  1093. X#define COPYRIGHT      \
  1094. X"ListProcessor version 6.0 by Anastasios Kotsikonas, Copyright (c) 1991-93.\n\
  1095. XUse, duplication or disclosure by the U.S. Federal Government is subject to the\n\
  1096. Xrestrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,\n\
  1097. Xfor U.S. Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).\n\n"
  1098. X#define SERVICE          "ulistproc"
  1099. X#define COMPLETE_FILE(f)  if (!interactive) fprintf (f, ".\nQUIT\n")
  1100. X#define TELNET          "telnet `hostname` 25 > /dev/null 2>&1 "
  1101. X#ifndef INEWS
  1102. X# define INEWS          "/usr/lib/news/inews"
  1103. X#endif
  1104. X#ifdef xenix
  1105. X# define BINMAIL      "/usr/bin/mail > /dev/null 2>&1"
  1106. X#else
  1107. X# define BINMAIL      "/bin/mail > /dev/null 2>&1"
  1108. X#endif
  1109. X
  1110. X#define SUBSCRIBERS       ".subscribers"
  1111. X#define ALIASES          ".aliases"
  1112. X#define NEWSF          ".news"
  1113. X#define PEERS          ".peers"
  1114. X#define HEADERS          ".headers"
  1115. X#define RESTRICTED        ".restricted"
  1116. X#define IGNORED           ".ignored"
  1117. X#define INFO_FILE         ".info"
  1118. X#define WELCOME_FILE      ".welcome"
  1119. X#define LIST_LIMITS      ".limits"
  1120. X#define UNPROC_MESSAGES      ".un.messages"
  1121. X#define UNPROC_SUBSCRIBERS ".un.subscriber"
  1122. X#define UNPROC_PEERS      ".un.peers"
  1123. X#define UNPROC_NEWS      ".un.news"
  1124. X#define UNPROC_DIGEST     ".un.digest" /* digest ready to send */
  1125. X#define DIGEST_TOC        ".digest.toc" /* digest table of contents */
  1126. X#define DIGEST_MSG        ".digest.msg" /* digest of messages */
  1127. X#define DIGEST_TIME       ".digest.time" /* time last digest sent */
  1128. X#define REPORT_LIST       ".report.list"
  1129. X#define REPORT_LIST_ACC   ".rep.list.acc"
  1130. X#define LIST_MAIL_FILE    "mail"
  1131. X#define LIST_MODERATED_F  "moderated"
  1132. X
  1133. X#define MESSAGE_IDS_F     ".message.ids"
  1134. X
  1135. X#define INDEX          "INDEX"
  1136. X#define DIRF          "DIR"
  1137. X#define DEFAULT_ARCHIVE      "listproc"
  1138. X
  1139. X#define START_OPTIONS     "-crs"         /* provide start options here */
  1140. X#ifndef apollo
  1141. X# define CUT          "cut"
  1142. X#else
  1143. X# define CUT          "/sys5.3/usr/bin/cut"
  1144. X#endif
  1145. X#define AWK               "awk" /* Do a 'which awk' for proper path */
  1146. X#ifdef _AIX
  1147. X# define UPTIME          "ruptime"
  1148. X#else
  1149. X# define UPTIME            "uptime"  /* 'which uptime'; may use ruptime */
  1150. X#endif
  1151. X#define MAILER_DAEMON     "<MAILER&~.+@.+\\.MAILER.+>|SMTP@|\
  1152. X<DA?EMON&~DEMON\\.CO\\.UK>|POST.*MAST|^ROOT| WPUSER|MMDF|^SMT.*|\\$EMD|\
  1153. XMRGATE|VMMAIL|MAIL.*SYSTEM|UUCP|-MAISER-|^MAL@|MAIL.+AGENT|TCPMAIL|BITMAIL|\
  1154. XMAILMAN|MAIL_SYSTEM|^LISTSERV|^LISTPROC|^SERVER"
  1155. X              /* Preserve upper case; put all possibilities above
  1156. X                 separated by a '|'; all of the above entries will
  1157. X                 be used to identify mailer daemon messages so
  1158. X                 they can get special treatment; entries are
  1159. X                 regular expressions */
  1160. X#define SUSP_SUBJECT      \
  1161. X"DELIVERY[ \t]+ERROR|\
  1162. XDELIVERY[ \t]+REPORT|\
  1163. XDELIVERY[ \t]+PROBLEM|\
  1164. XWARNING[ \t]+FROM[ \t]+UUCP|\
  1165. XUSER[ \t]+UNKNOWN|\
  1166. XUNDELIVER.+[ \t]MAIL|\
  1167. XUNDELIVER.+[ \t]MESSAGE|\
  1168. XPROBLEMS.+DELIVERING.+MAIL|\
  1169. XPROBLEMS.+DELIVERING.+MESSAGE|\
  1170. XCAN[ \t]*['NO]*T.+DELIVER.+MAIL|\
  1171. XUNABLE.+DELIVER.+MAIL|\
  1172. XUNABLE.+DELIVER.+MESSAGE|\
  1173. XFAILED[ \t]+MAIL|\
  1174. XFAILED[ \t]+MESSAGE|\
  1175. XMAIL[ \t]+FAILED|\
  1176. XMAIL[ \t]+RETURNED|\
  1177. XRETURNED[ \t]+MAIL|\
  1178. XSYSTEM[ \t]+ERROR|\
  1179. XMAIL.*[ \t]ERROR|\
  1180. XMAIL[ \t]+RECEIVED|\
  1181. XMESSAGE[ \t]+RECEIVED|\
  1182. XMESSAGE[ \t]+DELIVER|\
  1183. XMAIL[ \t]+DELIVER|\
  1184. XINTERCEPTED[ \t]+MAIL|\
  1185. XWAITING[ \t]+MAIL|\
  1186. XREAD[ \t]+RECEIPT|\
  1187. XRECEIPT[ \t]+NOTIFICATION|\
  1188. XSTATUS.+SIGNAL[ \t]+[0-9]+|\
  1189. X^ERROR[ \t]+CONDITION[ \t]+RE:|\
  1190. XAUTO[ \t]+REPLY|\
  1191. XAUTOMATIC[ \t]+REPLY|\
  1192. XAUTOMATICALLY[ \t]+GENERATED|\
  1193. XWAITING.+MAIL|\
  1194. XON[ \t]+VACATION|\
  1195. XVIA[ \t]+VACATION|\
  1196. XCONCIERGE[ \t]+NOTICE|\
  1197. XAWAY[ \t]+FROM.+MAIL|\
  1198. XCAN[ \t]*['NO]*T.+ANSWER|\
  1199. XCAN[ \t]*['NO]*T.+REPLY|\
  1200. XOUT[ \t]+OF[ \t]+TOWN|\
  1201. XUNSUBSCRIBE|\
  1202. XREMOVE[ \t]+ME|\
  1203. XADD[ \t]+ME|\
  1204. X^[ \t]*TEST[ \t]*$|\
  1205. X^[ \t]*TEST.+IGNORE|\
  1206. XPLEASE[ \t]+IGNORE"
  1207. X              /* List of suspicious subject lines; possible mail
  1208. X                 loop */
  1209. X#ifndef UCB_MAIL
  1210. X# define UCB_MAIL      "/usr/ucb/mail" /* Path to UCB mail program. Redefine
  1211. X              it if UCB mail is not installed on your system */
  1212. X#endif
  1213. X
  1214. X/*
  1215. X  These #define's should not be altered.
  1216. X*/
  1217. X
  1218. X#ifndef NSIG
  1219. X# ifdef MAXSIG
  1220. X#  define NSIG          MAXSIG
  1221. X# else
  1222. X#  define NSIG            32
  1223. X# endif
  1224. X#endif
  1225. X
  1226. X#define DEFAULT_ILP_PORT  372    /* As assigned by the IANA */
  1227. X#define MAX_COMMANDS      28    /* # of commands recognized */
  1228. X#ifndef MAX_EMAILS
  1229. X#define MAX_EMAILS      10    /* ListProcessor emails in one outgoing batch */
  1230. X#endif
  1231. X#define MAX_FILE_LENGTH   500    /* Number of lines of files when shrunk */
  1232. X#ifndef BUFFSIZ
  1233. X# define BUFFSIZ        8192    /* Socket buffer size */
  1234. X#endif
  1235. X#define DEFAULT_SERVER_ADDRESS       "listproc"
  1236. X#define DEFAULT_SERVER_CMDOPTIONS ""
  1237. X#define DEFAULT_SERVER_COMMENT      "Boston University ListProcessor"
  1238. X#define DEFAULT_MANAGER          "server"
  1239. X#define DEFAULT_PRECEDENCE      "bulk"
  1240. X#ifndef MAX_LINE
  1241. X# define MAX_LINE      1024
  1242. X#endif
  1243. X#define EOS          '\0'
  1244. X#define RESET(var)      (var[0]) = EOS
  1245. X#define BSD_PS          0x01
  1246. X#define    SYSV_PS          0x02
  1247. X#define    USE_TELNET      0x04
  1248. X#define USE_ENV_VAR      0x08
  1249. X#define USE_MY_SYSTEM      0x10
  1250. X#define BSD_MAIL      0x20
  1251. X#define POST_MAIL      0x40
  1252. X#define GATE_MAIL      0x80
  1253. X#define USE_SYSMAIL      0x100
  1254. X#define LIMIT_MSG      0x200
  1255. X#define LIMIT_FILES      0x400
  1256. X#define IGNR_INVLD_RQSTS  0x4000
  1257. X#define RELAXED_SYNTAX      0x8000
  1258. X#define NON_AUTO_SUB      0x10000
  1259. X#define CONCEAL_LIST      0x20000
  1260. X#define ARCHIVE_LIST      0x40000
  1261. X#define ARCHIVE_DIGEST      0x80000
  1262. X#define START_OF_MESSAGE  "From " /*  mail messages start w/ this string */
  1263. X#define ACK          "ACK"   /* Send message back to sender */
  1264. X#define NOACK          "NOACK" /* Do not send message back to sender */
  1265. X#define POSTPONE      "POSTPONE"  /* Postpone sending mail */
  1266. X#define DIGEST            "DIGEST" /* send mail in digests */
  1267. X#define MAX_SET_OPTIONS   4
  1268. X
  1269. X#define MAX_OWNER_PREFS   15
  1270. X#define CCSET          "CCSET"
  1271. X#define    CCSUB          "CCSUBSCRIBE" /* Copy owner on subscribe request */
  1272. X#define CCUNSUB          "CCUNSUBSCRIBE" /* Copy owner on unsubscribe req */
  1273. X#define CCREC          "CCRECIPIENTS"
  1274. X#define CCINFO          "CCINFORMATION"
  1275. X#define CCSTAT          "CCSTATISTICS"
  1276. X#define CCGET          "CCGET"
  1277. X#define CCINDEX          "CCINDEX"
  1278. X#define CCLISTS          "CCLISTS"
  1279. X#define CCRELEASE      "CCRELEASE"
  1280. X#define CCHELP          "CCHELP"
  1281. X#define CCPRIVATE      "CCPRIVATE"
  1282. X#define CCRUN          "CCRUN"
  1283. X#define CCERRORS      "CCERRORS" /* Copy owner on errors */
  1284. X#define CCALL          "CCALL" /* Copy onwer on all activities */
  1285. X
  1286. X#define ccset          0x01
  1287. X#define ccsub          0x02
  1288. X#define ccunsub          0x04
  1289. X#define ccrec          0x08
  1290. X#define ccinfo          0x10
  1291. X#define ccstat          0x20
  1292. X#define ccget          0x40
  1293. X#define ccindex          0x80
  1294. X#define cclists          0x100
  1295. X#define ccrelease      0x200
  1296. X#define cchelp          0x400
  1297. X#define ccprivate      0x800
  1298. X#define ccrun          0x1000
  1299. X#define ccerrors      0x2000
  1300. X#define ccall          ccset | ccsub | ccunsub | ccrec | ccinfo | ccstat |\
  1301. X              ccget | ccindex | cclists | ccrelease | cchelp |\
  1302. X              ccprivate | ccrun | ccerrors
  1303. X
  1304. X#define MAX_SIGNAL      NSIG    /* Highest system signal caught */
  1305. X#define BOOLEAN          unsigned int
  1306. X#ifndef TRUE
  1307. X# define TRUE          1
  1308. X#endif
  1309. X#ifndef FALSE
  1310. X# define FALSE          0
  1311. X#endif
  1312. X#define CANT_OPEN      (-1)
  1313. X#define CANT_LOCK      (-2)
  1314. X#define SUBSCRIBED      TRUE    /* Subscribed sender */
  1315. X#define NOTSUBSCRIBED      FALSE   /* Sender is not subscribed */
  1316. X#define NEWS          TRUE+1  /* News feed */
  1317. X#define PEER          TRUE+2  /* Peer messages */
  1318. X#define OWNER          TRUE+3  /* Sender is a list owner */
  1319. X#define MANAGER          TRUE+4  /* Sender is the manager */
  1320. X#define NEW_ARRIVAL      "\n--- NEW MAIL HAS ARRIVED ---\n"
  1321. X#define PROCESSING_BATCH  "\n--- PROCESSING BATCH REQUESTS ---\n"
  1322. X#define DIGEST_TIME_      "\n--- DIGEST TIME ---\n"
  1323. X#ifndef MAX_LISTS
  1324. X# define MAX_LISTS      11 /* It should be one more than # desired */
  1325. X#endif
  1326. X
  1327. X#define SEM_REQ_ID      0x01
  1328. X#define SEM_SYSFILES      0x02
  1329. X#define SEM_LISTFILES      0x04
  1330. X#define SEM_ARCHIVES      0x08
  1331. X#define SEM_DLVR_MAIL      0x10
  1332. X
  1333. X#define RECEIVED      "^(Received:[ \t])"
  1334. X#define FROM          "^(From:[ \t])"
  1335. X#define SUBJECT          "^(Subject:[ \t])"
  1336. X#define MESSAGE_ID1       "^(Message-Id:[ \t])"
  1337. X#define MESSAGE_ID2      "^(Message-ID:[ \t])"
  1338. X#define MESSAGE_ID3      "^(Message-id:[ \t])"
  1339. X#define MESSAGE_TAG      "^(Message-Tag:[ \t])"
  1340. X#define LISTPROC_ID      "^X-Listprocessor-Version:[ \t]|\
  1341. XX-Listserve?r?-Version:[ \t]|^Version:[ \t]"
  1342. X#define ERROR_CONDITION      "Error Condition Re: "
  1343. X#define PRECEDENCE      "^(Precedence:[ \t])"
  1344. X#define LOW_PRECEDENCES      "BULK|JUNK|LOW"
  1345. X
  1346. X#define COMPLETE_TELNET(f) \
  1347. X if (sys.options & USE_TELNET) \
  1348. X   COMPLETE_FILE (f)
  1349. X
  1350. X#define OPEN_FILE(fp, file, mode, func) \
  1351. X  if ((fp = fopen (file, mode)) == NULL)\
  1352. X    report_progress (report, tsprintf ("\n%s(): Could not open %s: errno %d",\
  1353. X                       func, file, errno), TRUE),\
  1354. X    gexit (1)
  1355. X
  1356. X#define COPY_OWNER(mask) (BOOLEAN)\
  1357. X((listid < 0 ? sys.server.manager_prefs : sys.lists[listid].owner_prefs) &\
  1358. X (mask))
  1359. X
  1360. X#define PREPEND(str, buf) \
  1361. X  { char copy [1024];\
  1362. X    RESET (copy);\
  1363. X    strcat (copy, buf);\
  1364. X    sprintf (buf, "%s%s", str, copy);\
  1365. X  }
  1366. X
  1367. X/*
  1368. X  System specific definitions:
  1369. X*/
  1370. X
  1371. X#if defined (sequent) || defined (unknown_port)
  1372. X# ifndef SEEK_SET
  1373. X#  define SEEK_SET    0
  1374. X# endif
  1375. X# ifndef SEEK_CUR
  1376. X#  define SEEK_CUR    1
  1377. X# endif
  1378. X#endif
  1379. X
  1380. X#if defined (_MINIX) || defined (ultrix) || defined (__NeXT__) || \
  1381. X  defined (apollo) || defined (i386)
  1382. X# ifndef NO_LOCKS
  1383. X#  define NO_LOCKS
  1384. X# endif
  1385. X# if !defined (bsd) && !defined (svr3) && !defined (svr4)
  1386. X#  define bsd
  1387. X# endif
  1388. X# ifndef ultrix
  1389. X#  undef GO_INTERACTIVE
  1390. X#  ifndef NO_ABORT_OP
  1391. X#   define NO_ABORT_OP
  1392. X#  endif
  1393. X# endif
  1394. X#endif
  1395. X
  1396. X#if defined (__convex__)
  1397. X# ifdef __STDC__
  1398. X#  ifndef NO_LOCKS
  1399. X#   define NO_LOCKS
  1400. X#  endif
  1401. X# endif
  1402. X# ifdef GO_INTERACTIVE
  1403. X#  undef GO_INTERACTIVE
  1404. X#  ifndef NO_ABORT_OP    /* Convex does define MSG_OOB, MSG_PEEK, SIOCATMARK */
  1405. X#   define NO_ABORT_OP
  1406. X#  endif
  1407. X# endif
  1408. X#endif
  1409. X
  1410. X#if defined (sun) || defined (hpux) || defined (__hpux) || \
  1411. X  defined (sequent) || defined (ultrix) || defined (__convex__) || \
  1412. X  defined (__NeXT__)
  1413. X# if !defined (bsd) && !defined (svr3) && !defined (svr4)
  1414. X#  define bsd
  1415. X# endif
  1416. X#endif
  1417. X
  1418. X#if defined (sgi) || defined (__sgi) || defined (mips) || defined (__mips) ||\
  1419. X  defined (_AIX) || defined (stellar) || defined (titan) || defined (xenix) ||\
  1420. X  defined (sco) || defined (M_UNIX) || defined (M_XENIX) || defined (__osf__) \
  1421. X  || defined (stardent) 
  1422. X# if !defined (svr3) && !defined (svr4) && !defined (bsd)
  1423. X#  define svr3
  1424. X# endif
  1425. X# ifdef xenix
  1426. X#  ifndef NO_LOCKS
  1427. X#   define NO_LOCKS
  1428. X#  endif
  1429. X# endif
  1430. X# if defined (titan) || defined (stellar) || defined (stardent)
  1431. X#  ifdef GO_INTERACTIVE
  1432. X#   undef GO_INTERACTIVE
  1433. X#  endif
  1434. X#  ifndef NO_ABORT_OP
  1435. X#   define NO_ABORT_OP
  1436. X#  endif
  1437. X# endif
  1438. X#endif
  1439. X
  1440. X#if defined (i860) || defined (__DGUX__)
  1441. X# if !defined (bsd) && !defined (svr3) && !defined (svr4)
  1442. X#  define svr4
  1443. X# endif
  1444. X#endif
  1445. X
  1446. X#define NONBLOCKING_IO
  1447. X
  1448. X#ifndef NO_ABORT_OP
  1449. X# define VERSION      "6.0c -- ListProcessor by Anastasios Kotsikonas"
  1450. X#else
  1451. X# define VERSION      "6.0 -- ListProcessor by Anastasios Kotsikonas"
  1452. X#endif
  1453. X
  1454. X/* If you do not have TCP/IP and are using Zmailer, provide the following
  1455. X   information about your host.
  1456. X*/
  1457. X#ifndef TCP_IP
  1458. X# define HOSTNAME      "localhost" /* Replace w/ your host's name */
  1459. X# define LOCAL_ADDR      "127.0.0.1" /* Replace w/ your host's IP address */
  1460. X#endif
  1461. X
  1462. X/*
  1463. X These functions don't have prototypes in SCO  in the included files.
  1464. X
  1465. Xextern void exit (int);
  1466. Xextern int unlink (char *);
  1467. Xextern int stat (char *, struct stat *);
  1468. Xextern int mkdir (char *, int);
  1469. Xextern int lockf (int, int, int);
  1470. Xextern int open (char *, int, ...);
  1471. Xextern int creat (char *, int);
  1472. Xextern int close (int);
  1473. Xextern int getpid ();
  1474. Xextern int stat (char *, struct stat *);
  1475. Xextern int chmod (char *, int);
  1476. Xextern int chdir (char *);
  1477. Xextern int unlink (char *);
  1478. Xextern unsigned int sleep (unsigned int);
  1479. Xextern int execl (char *, ...);
  1480. Xextern int read (int, void *, unsigned);
  1481. Xextern int write (int, void *, unsigned);
  1482. Xextern int umask (int);
  1483. Xextern char *getenv (char *);
  1484. Xextern void free (void *);
  1485. Xextern int kill (int, int);
  1486. Xextern int getuid (void);
  1487. Xextern int abort (void);
  1488. Xextern int access (char *, int);
  1489. Xextern void *calloc (int, int);
  1490. X*/
  1491. *-*-END-of-src/defs.h-*-*
  1492. echo x - src/global.h
  1493. sed 's/^X//' >src/global.h <<'*-*-END-of-src/global.h-*-*'
  1494. X/*
  1495. X  AGREEMENT: This software can be used and distributed freely only as a
  1496. X  whole and not in parts, as long as you do not remove or alter the author
  1497. X  and copyright notices in the file defs.h; this notices are #define'd in
  1498. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  1499. X  provided for your personal use, you may not alter the functions
  1500. X  create_header(), create_multi_recipient_header() and main() in list.c,
  1501. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  1502. X  any changes you may have made. No part of the source code bearing a
  1503. X  copyright notice can be included in commercial software systems without
  1504. X  written permission by the author.
  1505. X  By using this software you are bound by this agreement.
  1506. X  This software comes with no warranties and cannot be sold for profit.
  1507. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  1508. X  files when distributing this software.
  1509. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  1510. X  Use, duplication or disclosure by the Federal Government is subject to the
  1511. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  1512. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  1513. X*/
  1514. X
  1515. Xchar subscribersf [MAX_LINE];
  1516. Xchar newsf [MAX_LINE];
  1517. Xchar peersf [MAX_LINE];
  1518. Xchar aliasesf [MAX_LINE];
  1519. Xchar headersf [MAX_LINE];
  1520. Xchar restrictedf [MAX_LINE];
  1521. Xchar ignoredf [MAX_LINE];
  1522. Xchar list_mail_f [MAX_LINE];
  1523. Xchar list_moderated_f [MAX_LINE];
  1524. Xchar report_listf [MAX_LINE];
  1525. Xchar server_ignoredf [MAX_LINE];
  1526. Xchar infof [MAX_LINE];
  1527. Xchar welcomef [MAX_LINE];
  1528. Xchar unprocessed_messages [MAX_LINE];
  1529. Xchar unprocessed_subscribersf [MAX_LINE];
  1530. Xchar unprocessed_peersf [MAX_LINE];
  1531. Xchar unprocessed_newsf [MAX_LINE];
  1532. Xchar unprocessed_digestf [MAX_LINE];
  1533. Xchar message_idsf [MAX_LINE];
  1534. Xchar message_id [MAX_LINE];
  1535. Xchar digest_msgf [MAX_LINE];
  1536. Xchar digest_timef [MAX_LINE];
  1537. Xchar password_in_sub_file [MAX_LINE];
  1538. Xchar **alternate_addresses;
  1539. Xchar *prog;
  1540. XSYS  sys;
  1541. XCOMMANDS commands [MAX_COMMANDS]; /* Set of recognizable commands */
  1542. XREMOTE *rlists = NULL, *matched_rlists = NULL;
  1543. XBOOLEAN debug = FALSE;
  1544. X
  1545. X/*
  1546. X  Below are the valid SET options, their valid values and their
  1547. X  default values.
  1548. X*/
  1549. X
  1550. X/* valid SET options */
  1551. Xchar *options [] = { "ADDRESS", "MAIL", "PASSWORD", "CONCEAL" };
  1552. X
  1553. X/* and values */
  1554. Xchar *values [] =
  1555. X{ "^FIXED$|^VARIABLE$", "^ACK$|^NOACK$|^POSTPONE$|^DIGEST$", ".*", "^YES$|^NO$" };
  1556. X
  1557. Xchar *default_values [] = { "FIXED", "NOACK", ".*", "NO" };
  1558. X
  1559. *-*-END-of-src/global.h-*-*
  1560. echo x - src/ilp.h
  1561. sed 's/^X//' >src/ilp.h <<'*-*-END-of-src/ilp.h-*-*'
  1562. X/*
  1563. X  AGREEMENT: This software can be used and distributed freely only as a
  1564. X  whole and not in parts, as long as you do not remove or alter the author
  1565. X  and copyright notices in the file defs.h; this notices are #define'd in
  1566. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  1567. X  provided for your personal use, you may not alter the functions
  1568. X  create_header(), create_multi_recipient_header() and main() in list.c,
  1569. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  1570. X  any changes you may have made. No part of the source code bearing a
  1571. X  copyright notice can be included in commercial software systems without
  1572. X  written permission by the author.
  1573. X  By using this software you are bound by this agreement.
  1574. X  This software comes with no warranties and cannot be sold for profit.
  1575. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  1576. X  files when distributing this software.
  1577. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  1578. X  Use, duplication or disclosure by the Federal Government is subject to the
  1579. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  1580. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  1581. X
  1582. X  Below are the #define's pertinent to ilp.c and silp.c
  1583. X*/
  1584. X
  1585. X#include "ilpp.h"
  1586. X
  1587. X#define PORT                372    /* As assigned by IANA */
  1588. X#define MAX_HOPS        5    /* ... from ILP server to ILP server */
  1589. X#define TIMEOUT             180 /* How long to wait for server response */
  1590. X#define MSGLEN            8
  1591. X#ifndef BUFFSIZ
  1592. X# define BUFFSIZ             8192
  1593. X#endif
  1594. X#ifndef RESET
  1595. X# define RESET(v)            (v[0] = EOS)
  1596. X#endif
  1597. X#define PRINTF(code, str)    if (verbose) printf ("%d %s", code, str),\
  1598. X                fflush (stdout)
  1599. X#ifndef MIN
  1600. X# define MIN(a, b)        ((a) < (b) ? (a) : (b))
  1601. X#endif
  1602. X
  1603. X#define GENERAL_RESPONSES(cmd)\
  1604. X{\
  1605. X  switch (cmd) {\
  1606. X    case OK: PRINTF (OK, "OK\n"); break;\
  1607. X    case CONNECT: PRINTF (CONNECT, "Connected\n"); break;\
  1608. X    case SYNTAX_ERROR: PRINTF (SYNTAX_ERROR, "Syntax error in request\n");\
  1609. X     break;\
  1610. X    case INVALID_REQ: PRINTF (INVALID_REQ, "Invalid request\n"); break;\
  1611. X    case PEER_UNAVAIL: PRINTF (PEER_UNAVAIL, "Peer unavailable\n"); break;\
  1612. X    case BAD_ARCHIVE: PRINTF (BAD_ARCHIVE, "Bad archive\n"); break;\
  1613. X    case RESTRICTED_REQ: PRINTF (RESTRICTED_REQ,\
  1614. X     "Restriction in force for request\n"); break;\
  1615. X    case NOT_OWNER: PRINTF (NOT_OWNER, "Invalid onwer\n"); break;\
  1616. X    case SYS_ERROR: PRINTF (SYS_ERROR, "System error\n"); break;\
  1617. X    case MESSAGE: PRINTF (MESSAGE, "Message\n"); break;\
  1618. X    case PERMISSION_DENIED: PRINTF (PERMISSION_DENIED, "Permission denied\n");\
  1619. X     break;\
  1620. X    case CONN_CLOSED: PRINTF (CONN_CLOSED, "Closing connection\n"); break;\
  1621. X    case CONN_ABORTED: PRINTF (CONN_ABORTED, "Connection aborted\n");\
  1622. X     return -1; break;\
  1623. X    case CONN_TIMEOUT: PRINTF (CONN_TIMEOUT, "Connection timed out\n");\
  1624. X     return -1; break;\
  1625. X    case SERVER_BUSY: PRINTF (SERVER_BUSY, "Server busy\n"); break;\
  1626. X    case PASSWORD_REQUIRED: PRINTF (PASSWORD_REQUIRED, "Password required\n");\
  1627. X         if (read_from_fd (sock_fd, nbytes, NULL) < 0) return -1; break;\
  1628. X    case CONTINUED: PRINTF (CONTINUED, "[Command incomplete:]"); break;\
  1629. X    case MORE_INPUT_REQUIRED: PRINTF (MORE_INPUT_REQUIRED,\
  1630. X     "[Command incomplete:]"); break;\
  1631. X  }\
  1632. X}
  1633. *-*-END-of-src/ilp.h-*-*
  1634. echo x - src/ilpp.h
  1635. sed 's/^X//' >src/ilpp.h <<'*-*-END-of-src/ilpp.h-*-*'
  1636. X/*
  1637. X  AGREEMENT: This software can be used and distributed freely only as a
  1638. X  whole and not in parts, as long as you do not remove or alter the author
  1639. X  and copyright notices in the file defs.h; this notices are #define'd in
  1640. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  1641. X  provided for your personal use, you may not alter the functions
  1642. X  create_header(), create_multi_recipient_header() and main() in list.c,
  1643. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  1644. X  any changes you may have made. No part of the source code bearing a
  1645. X  copyright notice can be included in commercial software systems without
  1646. X  written permission by the author.
  1647. X  By using this software you are bound by this agreement.
  1648. X  This software comes with no warranties and cannot be sold for profit.
  1649. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  1650. X  files when distributing this software.
  1651. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  1652. X  Use, duplication or disclosure by the Federal Government is subject to the
  1653. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  1654. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  1655. X
  1656. X  Define the Interactive ListProcessor Protocol.
  1657. X*/
  1658. X
  1659. X#define OK                      100
  1660. X#define MORE_INPUT_REQUIRED    101
  1661. X#define CONTINUED        102
  1662. X#define PASSWORD_REQUIRED    103
  1663. X#define CONNECT            105
  1664. X#define MESSAGE            106
  1665. X#define WRITE_TO_FILE_ASC    110
  1666. X#define WRITE_TO_FILE_BIN    120
  1667. X#define APPEND_TO_FILE_ASC    130
  1668. X#define APPEND_TO_FILE_BIN    140
  1669. X#define TEST_FILE_PERMISSIONS    154
  1670. X#define SYNTAX_ERROR            200
  1671. X#define INVALID_REQ             300
  1672. X#define PEER_UNAVAIL            400
  1673. X#define BAD_ARCHIVE             500
  1674. X#define RESTRICTED_REQ          600
  1675. X#define NOT_OWNER               700
  1676. X#define SYS_ERROR               800
  1677. X#define PERMISSION_DENIED    860
  1678. X#define SERVER_BUSY             870
  1679. X#define CONN_TIMEOUT        880
  1680. X#define CONN_ABORTED        890
  1681. X#define CONN_CLOSED        900
  1682. *-*-END-of-src/ilpp.h-*-*
  1683. echo x - src/list.h
  1684. sed 's/^X//' >src/list.h <<'*-*-END-of-src/list.h-*-*'
  1685. X/* 
  1686. X  AGREEMENT: This software can be used and distributed freely only as a
  1687. X  whole and not in parts, as long as you do not remove or alter the author
  1688. X  and copyright notices in the file defs.h; this notices are #define'd in
  1689. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  1690. X  provided for your personal use, you may not alter the functions
  1691. X  create_header(), create_multi_recipient_header() and main() in list.c,
  1692. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  1693. X  any changes you may have made. No part of the source code bearing a
  1694. X  copyright notice can be included in commercial software systems without
  1695. X  written permission by the author.
  1696. X  By using this software you are bound by this agreement.
  1697. X  This software comes with no warranties and cannot be sold for profit.
  1698. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  1699. X  files when distributing this software.
  1700. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  1701. X  Use, duplication or disclosure by the Federal Government is subject to the
  1702. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  1703. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  1704. X
  1705. X  Below are the #define's pertinent to list.c
  1706. X
  1707. X  Preserve any quotes and new lines that appear below; change only path names.
  1708. X
  1709. X  ALWAYS SPECIFY ABSOLUTE PATHS.
  1710. X
  1711. X*/
  1712. X
  1713. X#ifdef __NeXT__
  1714. X# include "next.h"
  1715. X#endif
  1716. X
  1717. X#ifndef GRACE_PERIOD
  1718. X# define GRACE_PERIOD      604800  /* Time in secs after which offending */
  1719. X                  /* addresses are removed/suspended */
  1720. X#endif
  1721. X#define ONE_MONTH      2592000 /* 30 days: error messages in the database */
  1722. X                  /* older than this are removed */
  1723. X#ifndef SHELL_CHAR_LIMIT
  1724. X# define SHELL_CHAR_LIMIT 2048
  1725. X#endif
  1726. X#define INEWS_REPLY      "/tmp/.inews.reply"
  1727. X#define ERRORSF          ".errors"
  1728. X#define ERRORS2F      ".errors.tmp"
  1729. X#define UNPROC_TMP      ".un.tmp"
  1730. X#define MAIL_COPY      ".messages"
  1731. X#define MSG               ".msg"
  1732. X#undef MAILFORWARD
  1733. X#define MAILFORWARD       ".mailforward"
  1734. X#define HEADER          ".header"
  1735. X#define MSG_NO            ".msgno"
  1736. X#define DIGEST_NO         ".digestno"
  1737. X#define CHECKSUMS      ".sums"
  1738. X#define REMOVED_USERS      "removed.users"
  1739. X#define REMOVED_ALIASES      "removed.alias"
  1740. X#define MBOX              "mbox"            /* Place to save list's messages */
  1741. X#define ARCHIVE          "archive"        /* Public messages */
  1742. X#define ORIGIN          "^(Originator:[ \t])"
  1743. X#define SENDER            "^(Sender:[ \t])"
  1744. X#define REPLY_TO      "^(Reply-To:[ \t])"
  1745. X#define DATE              "^(Date:[ \t])"
  1746. X#define TO          "^(To:[ \t])"
  1747. X#define CC          "^(Cc:[ \t])"
  1748. X#define KEYWORDS      "^(Keywords:[ \t])"
  1749. X#define ARCHIVE_NAME      "^(archive-name:[ \t])"
  1750. X#define CONTROL          "^(Control:[ \t])"
  1751. X#define NO_RECIPIENT_FILE "NONE"
  1752. X#define MESSAGE_SEPARATOR \
  1753. X"----------------------- Message requiring your approval ----------------------"
  1754. X#define REQUESTS \
  1755. X"(^[ \t]*APPR?O?V?E?[ \t]+([A-Z0-9.@-]+)[ \t]+.+[ \t]+[0-9]+[ \t]*$)|\
  1756. X(^[ \t]*DISC?A?R?D?[ \t]+([A-Z0-9.@-]+)[ \t]+.+[ \t]+[0-9]+[ \t]*$)|\
  1757. X(^[ \t]*EDIT[ \t]+([A-Z0-9.@-]+)[ \t]+.+[ \t]+[A-Z]+[ \t]*$)|\
  1758. X(^[ \t]*GET[ \t]+[A-Z0-9/.-]+.+)|\
  1759. X(^[ \t]*HELP[ \t]*[A-Z0-9]*$)|\
  1760. X(^[ \t]*INDEX[ \t]*[A-Z0-9/.-]*.*)|\
  1761. X(^[ \t]*INFO?R?M?A?T?I?O?N?[ \t]+([A-Z0-9.@-]+)[ \t]*$)|\
  1762. X(^[ \t]*LIST?S?[ \t]*$)|\
  1763. X(^[ \t]*PUT[ \t]+([A-Z0-9.@-]+)[ \t]+.+)|\
  1764. X(^[ \t]*RECI?P?I?E?N?T?S?[ \t]+([A-Z0-9.@-]+)[ \t]*$)|\
  1765. X(^[ \t]*REVI?E?W?[ \t]+([A-Z0-9.@-]+)[ \t]*$)|\
  1766. X(^[ \t]*RELE?A?S?E?[ \t]*$)|\
  1767. X(^[ \t]*REPO?R?T?S?[ \t]+([A-Z0-9.@-]+)[ \t]+.+$)|\
  1768. X(^[ \t]*RUN[ \t]+([A-Z0-9.@-]+))|\
  1769. X(^[ \t]*SET[ \t]+([A-Z0-9.@-]+))|\
  1770. X(^[ \t]*STAT?I?S?T?I?C?S?[ \t]+([A-Z0-9.@-]+))|\
  1771. X(^[ \t]*SUBS?C?R?I?B?E?[ \t]+([A-Z0-9.@-]+).+)|\
  1772. X(^[ \t]*SYST?E?M?[ \t]+([A-Z0-9.@-]+)[ \t]+.+[ \t]+#.+)|\
  1773. X(^[ \t]*UNSU?B?S?C?R?I?B?E?[ \t]*([A-Z0-9.@-]*))|\
  1774. X(^[ \t]*SIGN?O?F?F?[ \t]*([A-Z0-9.@-]*))|\
  1775. X(^[ \t]*REMOVE[ \t]ME)|\
  1776. X(^[ \t]*PLEASE[ \t]+REMOVE[ \t]+)|\
  1777. X(^[ \t]*PLEASE[ \t]+UNSU?B?S?C?R?I?B?E?[ \t]+)|\
  1778. X(^[ \t]*PLEASE[ \t]+SIGN[ \t]+)|\
  1779. X(^[ \t]*PLEASE[ \t]+ADD[ \t]+)|\
  1780. X(^[ \t]*WHIC?H?[ \t]*$)|\
  1781. X(^[ \t]*SHUTDOWN[ \t]+.+$)|\
  1782. X(^[ \t]*RESTART[ \t]+.+$)|\
  1783. X(^[ \t]*EXEC?U?T?E?[ \t]+.+#.+)"
  1784. X
  1785. X#define APPEND_TELNET(func) \
  1786. X  if ((sys.options & USE_TELNET)) {\
  1787. X    if ((f = fopen (mailforwardf, "a")) == NULL)\
  1788. X      report_progress (report, tsprintf ("%s(): Could not open %s", func, \
  1789. X               mailforwardf), TRUE),\
  1790. X      gexit (1);\
  1791. X    COMPLETE_FILE (f);\
  1792. X    fclose (f);\
  1793. X  }
  1794. X
  1795. X#define DELIVER_MAIL(recipient) \
  1796. X  if (!interactive) {\
  1797. X    if ((++mails_sent) >= MAX_EMAILS)\
  1798. X      mails_sent = 0,\
  1799. X      sleep (30);\
  1800. X    if (sys.options & USE_SYSMAIL) \
  1801. X      sysmail (mailforwardf); \
  1802. X    else \
  1803. X      syscom ("%s '%s' < %s", sys.mail.method, \
  1804. X              (((sys.options & USE_TELNET) == 0) ? locase (recipient) : " "), \
  1805. X              mailforwardf);\
  1806. X  }
  1807. X
  1808. X#define NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS(__address__, __func__, from_sender) \
  1809. X  { char error [MAX_LINE];\
  1810. X    report_progress (report, tsprintf ("Syntax error in user address: %s\n%s",\
  1811. X __address__, (from_sender ? "Message not delivered to any recipients" : \
  1812. X"Message not delivered to this recipient")), TRUE);\
  1813. X    create_header (&f, mailforwardf, sys.server.address, sys.server.address,\
  1814. X           sys.manager, "Syntax error in user address", TRUE, FALSE,\
  1815. X           TRUE);\
  1816. X    fprintf (f, "Error detected in user address: %s\n", __address__);\
  1817. X    if (from_sender)\
  1818. X      fprintf (f, "Message not distributed to list %s.\n",\
  1819. Xsys.lists[listid].alias);\
  1820. X    else\
  1821. X      fprintf (f, "Message not delivered to this recipient.\n");\
  1822. X    fprintf (f, "The message is included below:\n\
  1823. X-----------------------------------------------------------------------------\n\
  1824. X");\
  1825. X    fclose (f);\
  1826. X    cat_append (headerf, mailforwardf);\
  1827. X    cat_append (msgf, mailforwardf);\
  1828. X    APPEND_TELNET (__func__);\
  1829. X    DELIVER_MAIL (sys.manager);\
  1830. X  }
  1831. X
  1832. X#define NOTIFY_OWNER_OF_MSG_IGNORED(__msg__, __sender__) \
  1833. X{ \
  1834. X  report_progress (report, tsprintf (__msg__, __sender__), TRUE);\
  1835. X  create_header (&f, mailforwardf, sys.lists[listid].address, \
  1836. X         sys.lists[listid].address, sys.lists[listid].owner, \
  1837. X         "Notification: message ignored", FALSE, FALSE, FALSE);\
  1838. X  fprintf (f, __msg__, __sender__);\
  1839. X  fprintf (f, "\n\nThe message is included below:\n\
  1840. X-----------------------------------------------------------------------------\n\
  1841. X");\
  1842. X  fclose (f);\
  1843. X  cat_append (headerf, mailforwardf);\
  1844. X  cat_append (msgf, mailforwardf);\
  1845. X  APPEND_TELNET ("process_message");\
  1846. X  DELIVER_MAIL (sys.lists[listid].owner);\
  1847. X}
  1848. X
  1849. X
  1850. X#define REMOVE_ADDRESS(address, __from__, __to__, append_to) \
  1851. X{\
  1852. X  FILE *fin, *fout;\
  1853. X  char line[MAX_LINE], linecopy[MAX_LINE], *error;\
  1854. X  long int len, written;\
  1855. X  OPEN_FILE (fin, __from__, "r", "process_message");\
  1856. X  OPEN_FILE (fout, __to__, "w", "process_message");\
  1857. X  while (!feof (fin)) {\
  1858. X    RESET (line);\
  1859. X    fgets (line, MAX_LINE - 2, fin);\
  1860. X    strcpy (linecopy, line);\
  1861. X    upcase (linecopy);\
  1862. X    if (line[0] != EOS) {\
  1863. X      if (linecopy[strlen (linecopy) - 1] == '\n')\
  1864. X    linecopy[strlen (linecopy) - 1] = EOS;\
  1865. X      if (removed || re_strcmp (address, linecopy, NULL) <= 0) {\
  1866. X    if ((written = write_to_fd (fileno (fout), line, (len = strlen (line))))\
  1867. X        < 0) {\
  1868. X      echo_append ((error = tsprintf ("write() failed; wrote %ld bytes \
  1869. Xout of %ld requested to file %s; errno %d", abs (written), len, __to__, errno)), WARNING);\
  1870. X      if (sys.options & BSD_MAIL)\
  1871. X        syscom ("echo '%s' | %s -s 'write() failed; system shut down' %s",\
  1872. X            error, UCB_MAIL, sys.manager);\
  1873. X      gexit (16);\
  1874. X    }\
  1875. X      }\
  1876. X      else {\
  1877. X        if (line[strlen (line) - 1] == '\n')\
  1878. X      line[strlen (line) - 1] = EOS;\
  1879. X    echo_append (line, append_to);\
  1880. X        removed = TRUE;\
  1881. X      }\
  1882. X    }\
  1883. X  }\
  1884. X  fclose (fin);\
  1885. X  fclose (fout);\
  1886. X}
  1887. X
  1888. X#define SUSPEND_ADDRESS(address, __from__, __to__) \
  1889. X{\
  1890. X  FILE *fin, *fout;\
  1891. X  char line [MAX_LINE], linecopy [MAX_LINE], addr [MAX_LINE], *error;\
  1892. X  long int len, written;\
  1893. X  OPEN_FILE (fin, __from__, "r", "process_message");\
  1894. X  OPEN_FILE (fout, __to__, "w", "process_message");\
  1895. X  while (!feof (fin)) {\
  1896. X    RESET (line);\
  1897. X    fgets (line, MAX_LINE - 2, fin);\
  1898. X    strcpy (linecopy, line);\
  1899. X    upcase (linecopy);\
  1900. X    if (line[0] != EOS) {\
  1901. X      if (linecopy[strlen (linecopy) - 1] == '\n')\
  1902. X    linecopy[strlen (linecopy) - 1] = EOS;\
  1903. X      if (suspended || re_strcmp (address, linecopy, NULL) <= 0) {\
  1904. X    if ((written = write_to_fd (fileno (fout), line, (len = strlen (line))))\
  1905. X        < 0) {\
  1906. X      echo_append ((error = tsprintf ("write() failed; wrote %ld bytes \
  1907. Xout of %ld requested to file %s; errno %d", abs (written), len, __to__, errno)), WARNING);\
  1908. X      if (sys.options & BSD_MAIL)\
  1909. X        syscom ("echo '%s' | %s -s 'write() failed; system shut down' %s",\
  1910. X            error, UCB_MAIL, sys.manager);\
  1911. X      gexit (16);\
  1912. X    }\
  1913. X      }\
  1914. X      else\
  1915. X    sscanf (line, "%s", addr),\
  1916. X    suspended = TRUE,\
  1917. X    fprintf (fout, "%s %s %s", addr, POSTPONE, skip_to_word (line, 3));\
  1918. X    }\
  1919. X  }\
  1920. X  fclose (fin);\
  1921. X  fclose (fout);\
  1922. X}
  1923. X
  1924. X#ifdef GO_INTERACTIVE
  1925. X# ifndef SYSLOG
  1926. X#  define IN_CRITICAL_SECTION(__func__, mask)\
  1927. X  if (sid >= 0) {\
  1928. X    int val;\
  1929. X    while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
  1930. X    if (P (sid, (mask)) < 0)\
  1931. X      report_progress (report, tsprintf ("\n%s(): Error P(); errno %d", \
  1932. X                     __func__, errno), TRUE),\
  1933. X      fclose (report),\
  1934. X      gexit (14);\
  1935. X  }
  1936. X# else
  1937. X#  define IN_CRITICAL_SECTION(__func__, mask)\
  1938. X  if (sid >= 0) {\
  1939. X    int val;\
  1940. X    while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
  1941. X    if (P (sid, (mask)) < 0)\
  1942. X      report_progress (report, tsprintf ("\n%s(): Error P(); errno %d", \
  1943. X                     __func__, errno), TRUE),\
  1944. X      gexit (14);\
  1945. X  }
  1946. X# endif
  1947. X
  1948. X# ifndef SYSLOG
  1949. X#  define OUT_OF_CRITICAL_SECTION(__func__, mask)\
  1950. X  if (sid >= 0 && V (sid, (mask)) < 0)\
  1951. X    report_progress (report, tsprintf ("\n%s(): Error V(); errno %d", \
  1952. X                       __func__, errno), TRUE),\
  1953. X    fclose (report),\
  1954. X    gexit (14);
  1955. X# else
  1956. X#  define OUT_OF_CRITICAL_SECTION(__func__, mask)\
  1957. X  if (sid >= 0 && V (sid, (mask)) < 0)\
  1958. X    report_progress (report, tsprintf ("\n%s(): Error V(); errno %d", \
  1959. X                       __func__, errno), TRUE),\
  1960. X    gexit (14);
  1961. X# endif
  1962. X#endif
  1963. X
  1964. Xchar digest_tocf [MAX_LINE];
  1965. Xchar mboxf [MAX_LINE];
  1966. Xchar msg_nof [MAX_LINE];
  1967. Xchar digest_nof [MAX_LINE];
  1968. Xchar msgf [MAX_LINE];
  1969. Xchar mailforwardf [MAX_LINE];
  1970. Xchar archivef [MAX_LINE];
  1971. Xchar headerf [MAX_LINE];
  1972. Xchar mail_copyf [MAX_LINE];
  1973. Xchar unprocessed_tmp [MAX_LINE];
  1974. Xchar removed_usersf [MAX_LINE];
  1975. Xchar removed_aliasesf [MAX_LINE];
  1976. Xchar archive_name [MAX_LINE];
  1977. Xchar limitsf [MAX_LINE];
  1978. Xchar errorsf [MAX_LINE];
  1979. Xchar errors2f [MAX_LINE];
  1980. Xchar checksumsf [MAX_LINE];
  1981. Xchar **multi_recipients;  /* List of multiple recipient addresses */
  1982. Xchar *list_alias  = NULL; /* arg to the -L command option */
  1983. Xchar *one_digest  = NULL; /* arg to the -i command option */
  1984. Xchar *mask, *archives_mask;
  1985. Xchar hostname [256];
  1986. X
  1987. XFILE *mail        = NULL; /* Source of messages */
  1988. XFILE *report      = NULL; /* Progress report to the administrator */
  1989. XFILE *subscribers = NULL; /* List of subscribers */
  1990. XFILE *news      = NULL; /* List of newsgroups */
  1991. XFILE *peers      = NULL; /* List of peers */
  1992. XFILE *restricted  = NULL; /* List of people whose messages require special
  1993. X                              handling */
  1994. XFILE *ignored     = NULL; /* List of people whose messages are ignored */
  1995. XFILE *msg_no      = NULL; /* Last message count */
  1996. XFILE *digest_no   = NULL; /* Last digest count */
  1997. XFILE *headers     = NULL; /* File containing headers of messages only */
  1998. XFILE *message_ids = NULL; /* File containing message ids */
  1999. X
  2000. XBOOLEAN tty_echo        = FALSE; /* -e option off */
  2001. XBOOLEAN send_to_subscribers = TRUE;  /* -r option off */
  2002. XBOOLEAN execute_once        = FALSE; /* -1 option off */
  2003. XBOOLEAN errors_to_owner        = FALSE; /* -f option off */
  2004. XBOOLEAN multi_recip        = FALSE; /* -m option off */
  2005. XBOOLEAN force_digest        = FALSE; /* -d option off */
  2006. XBOOLEAN is_moderated        = FALSE; /* -M option off */
  2007. XBOOLEAN article_replies_to_author  = FALSE; /* -p option off */
  2008. XBOOLEAN message_replies_to_author  = FALSE; /* -P option off */
  2009. XBOOLEAN do_not_check_subscriptions = FALSE; /* -s option off */
  2010. XBOOLEAN append_to_digest;         /* gets set if anyone wants digests */
  2011. XBOOLEAN message_rejected    = FALSE;
  2012. XBOOLEAN interactive        = FALSE;
  2013. XBOOLEAN no_compression        = FALSE;
  2014. X
  2015. Xint     returned_msg        = 0;     /* Counts the invalid messages */
  2016. Xint     public_msg        = 0;     /* Counts the public messages */
  2017. Xint     digest_msg        = 0;     /* Counts the digest messages */
  2018. Xint    mails_sent        = 0;     /* Counts email sent */
  2019. Xint     listid            = -1;
  2020. Xint    maxrecipients        = 0;
  2021. Xint    nlists            = 0;
  2022. Xint    sid            = -1;
  2023. X
  2024. Xtypedef struct _matched_prec_header {
  2025. X  char     *line;
  2026. X  struct _matched_prec_header *next;
  2027. X} MATCHED_PREC_HEADER;
  2028. X
  2029. XMATCHED_PREC_HEADER *matched_prec_header;
  2030. X
  2031. Xchar *mname[] = {
  2032. X  "jan", "feb", "mar", "apr", "may", "jun",
  2033. X  "jul", "aug", "sep", "oct", "nov", "dec",
  2034. X};
  2035. X
  2036. X/* The following warnings assume that the user address follows the SMTP
  2037. X   code where () are present -- not safe with messages from BITNET mailers.
  2038. X   list.c will have to be altered. Code still under testing. */
  2039. X
  2040. Xchar *warnings =    /* MAILER_DAEMON warnings */
  2041. X"^421 ([^ \t]+)|\
  2042. X^450 ([^ \t]+)|\
  2043. X^451 ([^ \t]+)|\
  2044. X^452 ([^ \t]+)|\
  2045. X^501 ([^ \t]+)|\
  2046. X^552 ([^ \t]+)|\
  2047. X^554 NO[ \t]+SUCH[ \t]+USER:?([^ \t]+)&~HOST[ \t]+UNKNOWN.+AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
  2048. X^554 ([^ \t]+)&~HOST[ \t]+UNKNOWN.+AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
  2049. XCONNECTION[ \t]+TIMED|\
  2050. XSERVICE[ \t]+UNAVAILABLE|\
  2051. XNETWORK[ \t]+IS[ \t]+UNREACHABLE|\
  2052. XUNKNOWN[ \t]+MAILER[ \t]+ERROR|\
  2053. XCONNECTION[ \t]+RESET|\
  2054. XREMOTE[ \t]+PROTOCOL[ \t]+ERROR|\
  2055. XTIMEOUT.+WAITING[ \t]+FOR[ \t]+INPUT|\
  2056. XPERMISSION[ \t]+DENIED|\
  2057. XCONNECTION[ \t]+ABORTED|\
  2058. XCONNECTION[ \t]+REFUSED|\
  2059. XQUOTA[ \t]+EXCEEDED|\
  2060. XDISK[ \t]+FULL|\
  2061. XUNKNOWN[ \t]+DOMAIN|\
  2062. XUNABLE.+SEND.+TO|\
  2063. XHOST[ \t]+UNKNOWN&~AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
  2064. XNEVER.+HEARD.+OF.+HOST&~AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
  2065. XUNABLE[ \t]+TO[ \t]+SEND[ \t]+MAIL";
  2066. X
  2067. Xchar *errors =        /* MAILER_DAEMON serious error messages */
  2068. X"UNKNOWN[ \t]+USER[ \t]+([^ \t]+)[ \t]+AT[ \t]+NODE[ \t]+([^ \t]+)|\
  2069. XNO[ \t]+SUCH[ \t]+USER[ \t]+([^ \t]+)[ \t]+AT[ \t]+NODE[ \t]+([^ \t]+)|\
  2070. XUNKNOWN[ \t]+USER[ \t]+([^ \t]+)[ \t]+AT[ \t]+SITE[ \t]+([^ \t]+)|\
  2071. XNO[ \t]+SUCH[ \t]+USER[ \t]+([^ \t]+)[ \t]+AT[ \t]+SITE[ \t]+([^ \t]+)|\
  2072. XUNKNOWN[ \t]+USER|\
  2073. XUSER[ \t]+UNKNOWN|\
  2074. XHOST[ \t]+UNKNOWN.+AUTHORITATIVE.+ANSWER.+FROM.+NAME.+SERVER|\
  2075. X^550 ";
  2076. X
  2077. Xchar *fatal_subjects =     /* Serious error messages in Subject: lines */
  2078. X"CAN.*T.+SEND.+FOR.+WEEK|\
  2079. XCAN.*T.+SEND.+FOR[ \t]+([^ \t]+)[ \t]+DAYS";
  2080. *-*-END-of-src/list.h-*-*
  2081. echo x - src/listproc.h
  2082. sed 's/^X//' >src/listproc.h <<'*-*-END-of-src/listproc.h-*-*'
  2083. X/*
  2084. X  AGREEMENT: This software can be used and distributed freely only as a
  2085. X  whole and not in parts, as long as you do not remove or alter the author
  2086. X  and copyright notices in the file defs.h; this notices are #define'd in
  2087. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  2088. X  provided for your personal use, you may not alter the functions
  2089. X  create_header(), create_multi_recipient_header() and main() in list.c,
  2090. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  2091. X  any changes you may have made. No part of the source code bearing a
  2092. X  copyright notice can be included in commercial software systems without
  2093. X  written permission by the author.
  2094. X  By using this software you are bound by this agreement.
  2095. X  This software comes with no warranties and cannot be sold for profit.
  2096. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  2097. X  files when distributing this software.
  2098. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  2099. X  Use, duplication or disclosure by the Federal Government is subject to the
  2100. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  2101. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  2102. X
  2103. X  Below are the #define's pertinent to listproc.c
  2104. X
  2105. X  Preserve any quotes and new lines that appear below; change only path names.
  2106. X
  2107. X  ALWAYS SPECIFY ABSOLUTE PATHS.
  2108. X
  2109. X*/
  2110. X
  2111. X#ifdef __STDC__
  2112. X# include "ansi/listproc.h"
  2113. X#else
  2114. X# include "nonansi/listproc.h"
  2115. X#endif
  2116. X#ifdef __NeXT__
  2117. X# include "next.h"
  2118. X#endif
  2119. X
  2120. X#define UPDATE_DATE      "July 12, 1994"
  2121. X#define REV_LEVEL      "6.0c/940712/0" /* Version/Original Release Date/Rev */
  2122. X#define RECIP_FILE        ".recip"
  2123. X#define USERS_FILE        "/tmp/users"
  2124. X#define PEER_SERVER_REQUEST "Peer Server Request:"
  2125. X#define START_OF_SIGNATURE "--"
  2126. X#define ALIASES_TIMESTAMPF ".time.aliases"
  2127. X#define IGNORED_TIMESTAMPF ".time.ignored"
  2128. X#define INFO_TIMESTAMPF    ".time.info"
  2129. X#define SUBSCRIBERS_TIMESTAMPF ".time.subscrib"
  2130. X#define WELCOME_TIMESTAMPF ".time.welcome"
  2131. X#define NEWS_TIMESTAMPF    ".time.news"
  2132. X#define PEERS_TIMESTAMPF   ".time.peers"
  2133. X
  2134. X#define DELIVER_MAIL(recipient, copy_owner) \
  2135. X{\
  2136. X  if (fax_it) \
  2137. X    syscom ("%s < %s %s > /dev/null &", sys.fax.prog,\
  2138. X        mailforwardf, sys.fax.fax_no);\
  2139. X  else if (!interactive) {\
  2140. X    if ((++mails_sent) >= MAX_EMAILS)\
  2141. X      mails_sent = 0,\
  2142. X      sleep (30);\
  2143. X    if (sys.options & USE_SYSMAIL) \
  2144. X      sysmail (mailforwardf); \
  2145. X    else \
  2146. X      syscom ("%s '%s' '%s' < %s", sys.mail.method, \
  2147. X              (((sys.options & USE_TELNET) == 0) ? locase (recipient) : " "), \
  2148. X          ((copy_owner) ? \
  2149. X           ((listid >= 0 ? sys.lists[listid].owner : sys.manager)) \
  2150. X           : " "), mailforwardf);\
  2151. X  }\
  2152. X}
  2153. X
  2154. X#define APPEND_TELNET(func) \
  2155. X  if (!interactive && !fax_it && (sys.options & USE_TELNET)) {\
  2156. X    if ((f = fopen (mailforwardf, "a")) == NULL)\
  2157. X      report_progress (report, tsprintf ("%s(): Could not open %s", func, \
  2158. X                     mailforwardf), TRUE),\
  2159. X      gexit (1);\
  2160. X    COMPLETE_FILE (f);\
  2161. X    fclose (f);\
  2162. X  }
  2163. X
  2164. X#define NOTIFY_MANAGER(msg) \
  2165. X{\
  2166. X  create_header (&f, mailforwardf, sys.server.address, sys.manager, sender,\
  2167. X         FALSE, OK, TRUE, FALSE);\
  2168. X  fprintf (f, "%s %s\n", msg, sender);\
  2169. X  COMPLETE_TELNET (f);\
  2170. X  fclose (f);\
  2171. X  DELIVER_MAIL (sys.manager, FALSE);\
  2172. X  report_progress (report, tsprintf ("%s %s; forwarding message to %s\n", msg,\
  2173. Xsender, sys.manager), FALSE);\
  2174. X}
  2175. X
  2176. X#define NOTIFY_MANAGER_OF_MSG_IGNORED(__msg__, __sender__, __func__) \
  2177. X{ \
  2178. X  report_progress (report, tsprintf (__msg__, __sender__), TRUE);\
  2179. X  create_header (&f, mailforwardf, sys.server.address, sys.manager, \
  2180. X         "Notification: request not processed", FALSE, OK, FALSE, FALSE);\
  2181. X  fprintf (f, __msg__, __sender__);\
  2182. X  fprintf (f, "\n\nCheck the top level mbox file and the report file; \
  2183. Xsender was %s\n", sender);\
  2184. X  fclose (f);\
  2185. X  APPEND_TELNET (__func__);\
  2186. X  DELIVER_MAIL (sys.manager, FALSE);\
  2187. X}
  2188. X
  2189. X#define NOTIFY_OF_BAD_ARCHIVE(msg, archive, reply_code) \
  2190. X{\
  2191. X  create_header (&f, mailforwardf, sys.server.address, sender, request,\
  2192. X         COPY_OWNER (ccerrors), reply_code, FALSE, TRUE);\
  2193. X  fprintf (f, msg, archive);\
  2194. X  COMPLETE_TELNET (f);\
  2195. X  fclose (f);\
  2196. X  DELIVER_MAIL (sender, COPY_OWNER (ccerrors));\
  2197. X}
  2198. X
  2199. X#define NOTIFY_OF_REQUEST_FORWARDING \
  2200. X{\
  2201. X  create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,\
  2202. X         OK, FALSE, FALSE);\
  2203. X  if (interactive) {\
  2204. X    int ret;\
  2205. X    REMOTE *r = matched_rlists;\
  2206. X    fclose (f);\
  2207. X    while (r) {\
  2208. X      if (r->inet_addr[0] != EOS) {\
  2209. X    f = fopen (mailforwardf, "a");\
  2210. X        fprintf (f, "*** %s: Contacting ListProcessor %s @ %s, port %d ...\n",\
  2211. X         hostname, r->listproc, r->inet_addr, r->port);\
  2212. X        fclose (f);\
  2213. X        if ((ret = silp (r->inet_addr, r->port, sender, "", 60, mailforwardf,\
  2214. X                 request)) < 0)\
  2215. X      reply_code (SYS_ERROR),\
  2216. X      f = fopen (mailforwardf, "a"),\
  2217. X      fprintf (f, "### %s: Local system error. Please send email.\n",\
  2218. X           hostname),\
  2219. X      fclose (f);\
  2220. X    else if (ret == PEER_UNAVAIL)\
  2221. X      f = fopen (mailforwardf, "a"),\
  2222. X      fprintf (f, "### %s: Peer unavailable. Please send email.\n",\
  2223. X           hostname),\
  2224. X      fclose (f);\
  2225. X    else if (ret == CONN_ABORTED)\
  2226. X      f = fopen (mailforwardf, "a"),\
  2227. X      fprintf (f, "### %s: Connection aborted. Please send email.\n",\
  2228. X           hostname),\
  2229. X      fclose (f);\
  2230. X    else if (ret == CONN_TIMEOUT)\
  2231. X      f = fopen (mailforwardf, "a"),\
  2232. X      fprintf (f, "### %s: Connection timed out. Please send email.\n",\
  2233. X           hostname),\
  2234. X      fclose (f);\
  2235. X    else if (ret == SERVER_BUSY)\
  2236. X      reply_code (SERVER_BUSY),\
  2237. X      f = fopen (mailforwardf, "a"),\
  2238. X      fprintf (f, "### %s: Remote server busy. Please send email.\n",\
  2239. X           hostname),\
  2240. X      fclose (f);\
  2241. X    else if (ret == SYS_ERROR)\
  2242. X      reply_code (SYS_ERROR),\
  2243. X      f = fopen (mailforwardf, "a"),\
  2244. X      fprintf (f, "### %s: Remote system error. Please send email.\n",\
  2245. X           hostname),\
  2246. X      fclose (f);\
  2247. X      }\
  2248. X      else\
  2249. X    f = fopen (mailforwardf, "a"),\
  2250. X    fprintf (f, "??? %s: ListProcessor %s cannot be contacted; please \
  2251. Xsend email.\n", hostname, r->listproc),\
  2252. X    fclose (f);\
  2253. X      r = r->next;\
  2254. X    }\
  2255. X    return;\
  2256. X  }\
  2257. X  fprintf (f, "List %s is not local. Your request is forwarded to the \
  2258. Xfollowing list\nserver(s):\n\n", sys.lists[nlists].alias);\
  2259. X  {\
  2260. X    REMOTE *r = matched_rlists;\
  2261. X    while (r)\
  2262. X      fprintf (f, "%s (List address: %s)\n", r->listproc, r->address),\
  2263. X      r = r->next;\
  2264. X  }\
  2265. X  fprintf (f, "\nYou may wish to send any such future requests to this/these \
  2266. Xserver(s).\n");\
  2267. X  COMPLETE_TELNET (f);\
  2268. X  fclose (f);\
  2269. X  DELIVER_MAIL (sender, FALSE);\
  2270. X}
  2271. X
  2272. X#define FORWARD_REQUEST \
  2273. X  {\
  2274. X    REMOTE *r = matched_rlists;\
  2275. X    while (r) {\
  2276. X      create_header (&f, mailforwardf, sender, r->listproc, "", FALSE, OK, \
  2277. X             FALSE, FALSE);\
  2278. X      fprintf (f, "%s\n", request);\
  2279. X      COMPLETE_TELNET (f);\
  2280. X      fclose (f);\
  2281. X      DELIVER_MAIL (r->listproc, FALSE);\
  2282. X      r = r->next;\
  2283. X    }\
  2284. X  }
  2285. X
  2286. X#define MEMBERS_ONLY \
  2287. X{\
  2288. X  BOOLEAN ok_to_reset_address = FALSE;\
  2289. X  if ((sys.lists[listid].defaults.set_values[0][0] == EOS &&\
  2290. X       !strcmp (default_values [0], "VARIABLE")) ||\
  2291. X      (!strcmp (sys.lists[listid].defaults.set_values[0], "VARIABLE")))\
  2292. X    ok_to_reset_address = TRUE;\
  2293. X  create_header (&f, mailforwardf, sys.server.address, sender, request,\
  2294. X         COPY_OWNER (ccprivate), RESTRICTED_REQ, FALSE, FALSE);\
  2295. X  fprintf (f, "%s: List %s is private for members only.\nOnly subscribers may \
  2296. Xissue this request.\n", sender, sys.lists[listid].alias);\
  2297. X  if (alternate_addresses) {\
  2298. X    fprintf (f, "\nIn addition, the system found the following \
  2299. Xaddress(es) that resemble yours.\nIf one of these is you, please resend your \
  2300. Xmessage from that one%s:\n\n",\
  2301. X         (ok_to_reset_address ? \
  2302. X          ", or use the\n'set <list> address' request to change the \
  2303. Xaddress you are subscribed with" :\
  2304. X          ""));\
  2305. X    {\
  2306. X      int i;\
  2307. X      for (i = 0; alternate_addresses[i]; ++i)\
  2308. X    fprintf (f, "%s\n", alternate_addresses[i]),\
  2309. X    free ((char *) alternate_addresses[i]);\
  2310. X      free ((char **) alternate_addresses);\
  2311. X      alternate_addresses = NULL;\
  2312. X      fprintf (f, "\n");\
  2313. X    }\
  2314. X  }\
  2315. X  COMPLETE_TELNET (f);\
  2316. X  fclose (f);\
  2317. X  DELIVER_MAIL (sender, COPY_OWNER (ccprivate));\
  2318. X}
  2319. X
  2320. X#define NOT_LIST_OWNER \
  2321. X{\
  2322. X  reject_mail (sender, request, tsprintf ("%s: You are not the owner of this \
  2323. Xlist\n", sender), NOT_OWNER, 0);\
  2324. X  if (!interactive) {\
  2325. X    create_header (&f, mailforwardf, sys.server.address,sys.lists[listid].owner,\
  2326. X           "WARNING: Hacker attack", FALSE, NOT_OWNER, TRUE, FALSE);\
  2327. X    fprintf (f, "The following request was sent to this ListProcessor by %s:\n\n%s\
  2328. X\nThe password provided appears in the report file\n",\
  2329. X         sender, request);\
  2330. X    COMPLETE_TELNET (f);\
  2331. X    fclose (f);\
  2332. X    DELIVER_MAIL (sys.lists[listid].owner, FALSE);\
  2333. X  }\
  2334. X}
  2335. X
  2336. X#define NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS(__address__) \
  2337. X{\
  2338. X  report_progress (report, "Syntax error in user address\n", FALSE);\
  2339. X  create_header (&f, mailforwardf, sys.server.address, sys.manager,\
  2340. X                 "Syntax error in user address", FALSE, SYNTAX_ERROR, TRUE,\
  2341. X         TRUE);\
  2342. X  if (request [0] != EOS)\
  2343. X    fprintf (f, ">%s\n", request);\
  2344. X  fprintf (f, "Error detected in user address: %s\nNo requests processed.\n",\
  2345. X __address__);\
  2346. X  COMPLETE_TELNET (f);\
  2347. X  fclose (f);\
  2348. X  DELIVER_MAIL (sys.manager, FALSE);\
  2349. X}
  2350. X
  2351. X#define NO_SUCH_MESSAGE_TAG(_tag_)\
  2352. X{\
  2353. X  create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,\
  2354. X         SYNTAX_ERROR, FALSE, TRUE);\
  2355. X  fprintf (f, "No message found with tag number %d.\n", _tag_);\
  2356. X  COMPLETE_TELNET (f);\
  2357. X  fclose (f);\
  2358. X  DELIVER_MAIL (sender, FALSE);\
  2359. X}
  2360. X
  2361. X#define CANNOT_STAT_FILE(_file_, _symptom_)\
  2362. X{\
  2363. X  create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,\
  2364. X         SYS_ERROR, FALSE, TRUE);\
  2365. X  fprintf (f, "Cannot %s file %s.\nYour request has to be resubmitted.\n",\
  2366. X_symptom_, _file_);\
  2367. X  COMPLETE_TELNET (f);\
  2368. X  fclose (f);\
  2369. X  DELIVER_MAIL (sender, FALSE);\
  2370. X}
  2371. X
  2372. X#define COMMAND(index, _name_, _mask_, _func_)\
  2373. X  commands[index].name = _name_;\
  2374. X  commands[index].mask = _mask_;\
  2375. X  commands[index].func = (FUNC) _func_
  2376. X
  2377. X#define PUT_TIMESTAMP(_targetfile_, _stampfile_) \
  2378. X  stat (_targetfile_, &stat_buf);\
  2379. X  echo (tsprintf ("%d", stat_buf.st_mtime), _stampfile_)
  2380. X
  2381. X#define COPY_MESSAGE \
  2382. X{\
  2383. X  char *error;\
  2384. X  long int len, written;\
  2385. X  sign[0] = RESET (line);\
  2386. X  signature = FALSE;\
  2387. X  sprintf (sign, "%s\n", START_OF_SIGNATURE);\
  2388. X  while (!feof (mail) && /* Copy till eof or next message */\
  2389. X         (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {\
  2390. X    if (!strcmp (line, sign))\
  2391. X      signature = TRUE;\
  2392. X    else if (!signature)\
  2393. X      if ((written = write_to_fd (fileno (f), line, (len = strlen (line)))) \
  2394. X      < 0) {\
  2395. X    echo_append ((error = tsprintf ("write() failed; wrote %ld bytes \
  2396. Xout of %ld requested; errno %d", abs (written), len, errno)), WARNING);\
  2397. X    if (sys.options & BSD_MAIL)\
  2398. X      syscom ("echo '%s' | %s -s 'write() failed; system shut down' %s",\
  2399. X          error, UCB_MAIL, sys.manager);\
  2400. X    gexit (16);\
  2401. X      }\
  2402. X    RESET (line);\
  2403. X    fgets (line, MAX_LINE - 2, mail);\
  2404. X  }\
  2405. X  if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))\
  2406. X    fseek (mail, -strlen (line), SEEK_CUR); /* Move back to beginning */\
  2407. X}
  2408. X
  2409. X#ifdef GO_INTERACTIVE
  2410. X# ifndef SYSLOG
  2411. X#  define IN_CRITICAL_SECTION(__func__, mask)\
  2412. X  if (sid >= 0) {\
  2413. X    int val;\
  2414. X    while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
  2415. X    if (P (sid, (mask)) < 0)\
  2416. X      report_progress (report, tsprintf ("\n%s(): Error P(); errno %d",\
  2417. X                     __func__, errno), TRUE),\
  2418. X      fclose (report),\
  2419. X      gexit (14);\
  2420. X  }
  2421. X# else
  2422. X#  define IN_CRITICAL_SECTION(__func__, mask)\
  2423. X  if (sid >= 0) {\
  2424. X    int val;\
  2425. X    while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
  2426. X    if (P (sid, (mask)) < 0)\
  2427. X      report_progress (report, tsprintf ("\n%s(): Error P(); errno %d",\
  2428. X                     __func__, errno), TRUE),\
  2429. X      gexit (14);\
  2430. X  }
  2431. X# endif
  2432. X
  2433. X# ifndef SYSLOG
  2434. X#  define OUT_OF_CRITICAL_SECTION(__func__, mask)\
  2435. X  if (sid >= 0 && V (sid, (mask)) < 0)\
  2436. X    report_progress (report, tsprintf ("\n%s(): Error V(); errno %d",\
  2437. X                       __func__, errno), TRUE),\
  2438. X    fclose (report),\
  2439. X    gexit (14);
  2440. X# else
  2441. X#  define OUT_OF_CRITICAL_SECTION(__func__, mask)\
  2442. X  if (sid >= 0 && V (sid, (mask)) < 0)\
  2443. X    report_progress (report, tsprintf ("\n%s(): Error V(); errno %d",\
  2444. X                       __func__, errno), TRUE),\
  2445. X    gexit (14);
  2446. X# endif
  2447. X#endif
  2448. X
  2449. X#ifdef GO_INTERACTIVE
  2450. X# define FORCE_EDIT \
  2451. X  OUT_OF_CRITICAL_SECTION ("put", SEM_LISTFILES);\
  2452. X  if (!interactive) /* No need to force EDIT for a live request */\
  2453. X    get_sys_files ("EDIT", params_copy, sender);
  2454. X#else
  2455. X# define FORCE_EDIT \
  2456. X  if (!interactive) /* No need to force EDIT for a live request */\
  2457. X    get_sys_files ("EDIT", params_copy, sender);
  2458. X#endif
  2459. X
  2460. X#define CHECK_TIMESTAMP(_stampfile_, _targetfile_)\
  2461. X  if ((f = fopen (_stampfile_, "r")) != NULL) {\
  2462. X    fscanf (f, "%d\n", ×tamp);\
  2463. X    fclose (f);\
  2464. X    stat (_targetfile_, &stat_buf);\
  2465. X    if (stat_buf.st_mtime != timestamp) {\
  2466. X      create_header (&f, mailforwardf, sys.server.address, sender, request,\
  2467. X             FALSE, PERMISSION_DENIED, FALSE, TRUE);\
  2468. X      fprintf (f, "File %s has been modified since you last\nedited it. The \
  2469. Xfile has to be reedited again.\n%s\
  2470. XYour PUT request is returned to you unprocessed below:\
  2471. X\n\n%s\n", _targetfile_, \
  2472. X(!interactive ? \
  2473. X"An EDIT request will be forced now and the new file will arrive \
  2474. Xin a separate\nmessage.\n\n" : ""), \
  2475. Xrequest);\
  2476. X      fflush (f);\
  2477. X      COPY_MESSAGE;\
  2478. X      COMPLETE_TELNET (f);\
  2479. X      fclose (f);\
  2480. X      DELIVER_MAIL (sender, FALSE);\
  2481. X      upcase (sender);\
  2482. X      FORCE_EDIT;\
  2483. X      return;\
  2484. X    }\
  2485. X  }
  2486. X
  2487. X#define REMOVE_ADDRESS(address, __from__, __to__) \
  2488. X{\
  2489. X  FILE *fin, *fout;\
  2490. X  long int len, written;\
  2491. X  char line[MAX_LINE], linecopy[MAX_LINE], *error;\
  2492. X  BOOLEAN removed = FALSE;\
  2493. X  OPEN_FILE (fin, __from__, "r", "unsubscribe");\
  2494. X  OPEN_FILE (fout, __to__, "w", "unsubscribe");\
  2495. X  while (!feof (fin)) {\
  2496. X    RESET (line);\
  2497. X    fgets (line, MAX_LINE - 2, fin);\
  2498. X    strcpy (linecopy, line);\
  2499. X    upcase (linecopy);\
  2500. X    if (line[0] != EOS) {\
  2501. X      if (linecopy[strlen (linecopy) - 1] == '\n')\
  2502. X    linecopy[strlen (linecopy) - 1] = EOS;\
  2503. X      if (removed || re_strcmp (address, linecopy, NULL) <= 0) {\
  2504. X    if ((written = write_to_fd (fileno (fout), line, (len = strlen (line))))\
  2505. X        < 0) {\
  2506. X      echo_append ((error = tsprintf ("write() failed; wrote %ld bytes \
  2507. Xout of %ld requested to file %s; errno %d", abs (written), len, __to__, errno)), WARNING);\
  2508. X      if (sys.options & BSD_MAIL)\
  2509. X        syscom ("echo '%s' | %s -s 'write() failed; system shut down' %s",\
  2510. X            error, UCB_MAIL, sys.manager);\
  2511. X      gexit (16);\
  2512. X    }\
  2513. X      }\
  2514. X      else\
  2515. X    removed = TRUE;\
  2516. X    }\
  2517. X  }\
  2518. X  fclose (fin);\
  2519. X  fclose (fout);\
  2520. X}
  2521. X
  2522. X#define THANKS    "THANK|GRACIAS|TODA|MERCI|DANK|ARIGATO|XIE.*XIE|DZENKUJEM|\
  2523. XTAK|D'AKUJEM|MAHALO|BEDANKT|GROET|E.[XH]AR[IH]ST[OW]|SINCERELY|TRULY|LATER|\
  2524. XSPOCIBO|END|QUIT"
  2525. X
  2526. X
  2527. Xchar recipf [MAX_LINE];      /* path to list + RECIP_FILE */
  2528. Xchar requests_file [MAX_LINE];
  2529. Xchar original_params [10240];
  2530. Xchar aliases_timestampf [MAX_LINE];
  2531. Xchar ignored_timestampf [MAX_LINE];
  2532. Xchar info_timestampf [MAX_LINE];
  2533. Xchar subscribers_timestampf [MAX_LINE];
  2534. Xchar welcome_timestampf [MAX_LINE];
  2535. Xchar news_timestampf [MAX_LINE];
  2536. Xchar peers_timestampf [MAX_LINE];
  2537. X
  2538. XFILE *mail        = NULL; /* Source of messages */
  2539. XFILE *report      = NULL; /* Progress report to the administrator */
  2540. XFILE *ignored     = NULL; /* List of people whose messages are ignored */
  2541. XFILE *msg_no      = NULL; /* Last message count */
  2542. XFILE *message_ids = NULL; /* List of message ids */
  2543. X
  2544. Xint     sid            = -1;
  2545. Xint      listid            = -1;
  2546. Xint      request_no        = 0;    /* Counts the public messages */
  2547. Xint      nlists            = -1;    /* # of lists defined in CONFIG */
  2548. Xint     mails_sent        = 0;    /* Count mail sent */
  2549. Xlong int restricted_commands    = 0;    /* Mask of restrictions */
  2550. Xlong int disabled_commands    = 0;    /* Mask for disabling commands */
  2551. Xlong int batched_commands    = 0;    /* Mask for batching commands */
  2552. XBOOLEAN  one_rejection        = FALSE;
  2553. XBOOLEAN  restart_sys        = FALSE;
  2554. XBOOLEAN  tty_echo        = FALSE;    /* -e option off */
  2555. XBOOLEAN  do_not_notify_peer_server = FALSE;
  2556. XBOOLEAN  peer_server_request    = FALSE;
  2557. XBOOLEAN  process_batch        = FALSE;    /* -B option off */
  2558. XBOOLEAN  interactive        = FALSE;    /* -i option off */
  2559. XBOOLEAN  fax_it            = FALSE;
  2560. Xchar     *mailforwardf        = NULL;
  2561. Xchar     *replyf        = NULL;
  2562. Xchar     hostname [256];
  2563. X
  2564. X/* Codes for helpful messages when a request is rejected. */
  2565. X#define REJECT_LIST    1
  2566. X#define REJECT_REQUEST    2
  2567. X#define REJECT_NAME    3
  2568. X#define REJECT_AT    4
  2569. *-*-END-of-src/listproc.h-*-*
  2570. echo x - src/next.h
  2571. sed 's/^X//' >src/next.h <<'*-*-END-of-src/next.h-*-*'
  2572. X/*
  2573. X  #define's specific to NeXT hosts.
  2574. X*/
  2575. X
  2576. X#ifndef S_IRWXU
  2577. X# define     S_IRWXU 0000700 /* rwx, owner */
  2578. X#endif
  2579. X#ifndef S_IRUSR
  2580. X# define         S_IRUSR 0000400 /* read permission, owner */
  2581. X#endif
  2582. X#ifndef S_IWUSR
  2583. X# define         S_IWUSR 0000200 /* write permission, owner */
  2584. X#endif
  2585. X#ifndef S_IXUSR
  2586. X# define         S_IXUSR 0000100 /* execute/search permission, owner */
  2587. X#endif
  2588. X#ifndef S_IRWXG
  2589. X# define     S_IRWXG 0000070 /* rwx, group */
  2590. X#endif
  2591. X#ifndef S_IRGRP
  2592. X# define         S_IRGRP 0000040 /* read permission, group */
  2593. X#endif
  2594. X#ifndef S_IWGRP
  2595. X# define         S_IWGRP 0000020 /* write permission, grougroup */
  2596. X#endif
  2597. X#ifndef S_IXGRP
  2598. X# define         S_IXGRP 0000010 /* execute/search permission, group */
  2599. X#endif
  2600. X#ifndef S_IRWXO
  2601. X# define     S_IRWXO 0000007 /* rwx, other */
  2602. X#endif
  2603. X#ifndef S_IROTH
  2604. X# define         S_IROTH 0000004 /* read permission, other */
  2605. X#endif
  2606. X#ifndef S_IWOTH
  2607. X# define         S_IWOTH 0000002 /* write permission, other */
  2608. X#endif
  2609. X#ifndef S_IXOTH
  2610. X# define         S_IXOTH 0000001 /* execute/search permission, other */
  2611. X#endif
  2612. *-*-END-of-src/next.h-*-*
  2613. echo x - src/pqueue.h
  2614. sed 's/^X//' >src/pqueue.h <<'*-*-END-of-src/pqueue.h-*-*'
  2615. X/*
  2616. X  AGREEMENT: This software can be used and distributed freely only as a
  2617. X  whole and not in parts, as long as you do not remove or alter the author
  2618. X  and copyright notices in the file defs.h; this notices are #define'd in
  2619. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  2620. X  provided for your personal use, you may not alter the functions
  2621. X  create_header(), create_multi_recipient_header() and main() in list.c,
  2622. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  2623. X  any changes you may have made. No part of the source code bearing a
  2624. X  copyright notice can be included in commercial software systems without
  2625. X  written permission by the author.
  2626. X  By using this software you are bound by this agreement.
  2627. X  This software comes with no warranties and cannot be sold for profit.
  2628. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  2629. X  files when distributing this software.
  2630. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  2631. X  Use, duplication or disclosure by the Federal Government is subject to the
  2632. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  2633. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  2634. X
  2635. X  Below are the #define's pertinent to pqueue.c
  2636. X
  2637. X  Preserve any quotes and new lines that appear below; change only path names.
  2638. X
  2639. X  ALWAYS SPECIFY ABSOLUTE PATHS.
  2640. X
  2641. X*/
  2642. X
  2643. X#ifdef __NeXT__
  2644. X# include "next.h"
  2645. X#endif
  2646. X
  2647. XFILE    *report        = NULL;  /* Progress report */
  2648. XBOOLEAN tty_echo    = FALSE; /* -e option off */
  2649. Xint    lfd        = 2;
  2650. Xint    listid        = -1;    /* Dummy */
  2651. Xint    sid        = -1;
  2652. *-*-END-of-src/pqueue.h-*-*
  2653. echo x - src/regexp.h
  2654. sed 's/^X//' >src/regexp.h <<'*-*-END-of-src/regexp.h-*-*'
  2655. X/*
  2656. X * Definitions etc. for regexp(3) routines.
  2657. X *
  2658. X * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
  2659. X * not the System V one.
  2660. X */
  2661. X#define NSUBEXP  10
  2662. Xtypedef struct regexp {
  2663. X    char *startp[NSUBEXP];
  2664. X    char *endp[NSUBEXP];
  2665. X    char regstart;        /* Internal use only. */
  2666. X    char reganch;        /* Internal use only. */
  2667. X    char *regmust;        /* Internal use only. */
  2668. X    int regmlen;        /* Internal use only. */
  2669. X    char program[1];    /* Unwarranted chumminess with compiler. */
  2670. X} regexp;
  2671. X
  2672. Xextern regexp *regcomp();
  2673. Xextern int regexec();
  2674. Xextern void regsub();
  2675. Xextern void regerror();
  2676. *-*-END-of-src/regexp.h-*-*
  2677. echo x - src/regmagic.h
  2678. sed 's/^X//' >src/regmagic.h <<'*-*-END-of-src/regmagic.h-*-*'
  2679. X/*
  2680. X * The first byte of the regexp internal "program" is actually this magic
  2681. X * number; the start node begins in the second byte.
  2682. X */
  2683. X#define    MAGIC    0234
  2684. *-*-END-of-src/regmagic.h-*-*
  2685. echo x - src/serverd.h
  2686. sed 's/^X//' >src/serverd.h <<'*-*-END-of-src/serverd.h-*-*'
  2687. X/*
  2688. X  AGREEMENT: This software can be used and distributed freely only as a
  2689. X  whole and not in parts, as long as you do not remove or alter the author
  2690. X  and copyright notices in the file defs.h; this notices are #define'd in
  2691. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  2692. X  provided for your personal use, you may not alter the functions
  2693. X  create_header(), create_multi_recipient_header() and main() in list.c,
  2694. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  2695. X  any changes you may have made. No part of the source code bearing a
  2696. X  copyright notice can be included in commercial software systems without
  2697. X  written permission by the author.
  2698. X  By using this software you are bound by this agreement.
  2699. X  This software comes with no warranties and cannot be sold for profit.
  2700. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  2701. X  files when distributing this software.
  2702. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  2703. X  Use, duplication or disclosure by the Federal Government is subject to the
  2704. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  2705. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  2706. X
  2707. X  Below are the #define's pertinent to serverd.c
  2708. X
  2709. X  ALWAYS SPECIFY ABSOLUTE PATHS.
  2710. X
  2711. X*/
  2712. X
  2713. X#ifdef __STDC__
  2714. X# include "ansi/serverd.h"
  2715. X#else
  2716. X# include "nonansi/serverd.h"
  2717. X#endif
  2718. X
  2719. X#ifdef __NeXT__
  2720. X# include "next.h"
  2721. X#endif
  2722. X
  2723. X#define MAX_TRIES     10        /* wait MAX_TRIES * 30 seconds */
  2724. X
  2725. XFILE    *report        = NULL;
  2726. XBOOLEAN tty_echo    = FALSE;    /* -e option off */
  2727. X
  2728. Xstruct _list_limits {
  2729. X  char list_limitsf [MAX_LINE],
  2730. X       list_mail_f [MAX_LINE],
  2731. X       digest_msgf [MAX_LINE],
  2732. X       digest_timef [MAX_LINE];
  2733. X  int  nmessages;
  2734. X  long int current_date;
  2735. X  BOOLEAN done_for_the_day;
  2736. X} lists [MAX_LISTS];
  2737. X
  2738. Xchar *exit_string[] = {  /* Define exit status strings */
  2739. X/* 0 */ "OK", 
  2740. X/* 1 */ "Could not open or lock file", 
  2741. X/* 2 */ "SIGINT signal",
  2742. X/* 3 */ "Command line option error",
  2743. X/* 4 */ "Syntax error in file",
  2744. X/* 5 */ "Could not spawn",
  2745. X/* 6 */ "Shutdown request",
  2746. X/* 7 */ "Restart request",
  2747. X/* 8 */ "Received system signal",
  2748. X/* 9 */ "Too many multiple recipients",
  2749. X/* 10 */"Could not deliver mail",
  2750. X/* 11 */"Malloc failed",
  2751. X/* 12 */"Cannot fork",
  2752. X/* 13 */"Socket connection problem",
  2753. X/* 14 */"Semaphore error",
  2754. X/* 15 */"Cannot setuid, setgid",
  2755. X/* 16 */"Internal error",
  2756. X/* 17 */"Unknown exit status"
  2757. X};
  2758. X
  2759. X#ifdef GO_INTERACTIVE
  2760. XBOOLEAN interactive    = FALSE;    /* -i option off */
  2761. X#endif
  2762. Xint    lfd     = 2;
  2763. Xint    nlists;
  2764. Xint    ppid;
  2765. X
  2766. X#ifndef WAIT3_NEEDS_UNION
  2767. X# if defined (sequent) || defined (stardent) || defined (stellar) || \
  2768. X  defined (titan) || defined (unknown_port)
  2769. X#  ifdef WEXITSTATUS
  2770. X#   undef WEXITSTATUS
  2771. X#  endif
  2772. X#  ifdef WTERMSIG
  2773. X#   undef WTERMSIG
  2774. X#  endif
  2775. X#  ifdef WIFSIGNALED
  2776. X#   undef WIFSIGNALED
  2777. X#  endif
  2778. X#  ifdef WIFEXITED
  2779. X#   undef WIFEXITED
  2780. X#  endif
  2781. X# endif
  2782. X#endif
  2783. X
  2784. X#ifndef WEXITSTATUS
  2785. X# define  WEXITSTATUS(stat)    ((int)(((stat)>>8)&0377))
  2786. X#endif
  2787. X
  2788. X#ifdef GO_INTERACTIVE
  2789. X# ifndef WTERMSIG
  2790. X#  define WTERMSIG(stat)    (((int)((stat)&0377))&0177)
  2791. X# endif
  2792. X# ifndef WIFSIGNALED
  2793. X#  define WIFSIGNALED(stat)    (((int)((stat)&0377))>0&&((int)(((stat)>>8)&\
  2794. X                0377))==0)
  2795. X# endif
  2796. X# ifndef WIFEXITED
  2797. X#  define WIFEXITED(stat)    (((int)((stat)&0377))==0)
  2798. X# endif
  2799. X# include "ilpp.h"
  2800. X
  2801. X# ifndef MAX_CONNECTIONS
  2802. X#  define MAX_CONNECTIONS 5
  2803. X# endif
  2804. X# define MSGLEN        8
  2805. X# define TIMEOUT_SIG    SIGUSR1    /* Signal sent when client is preempted */
  2806. X# define ABORT_SIG    SIGUSR2 /* Signal sent when server shuts down */
  2807. X
  2808. X# define LOGIN        "email address [none]: "
  2809. X# define PASSWORD    "Password: "
  2810. X# define PROMPT        "request> "
  2811. X# define CONT_PROMPT    "> "
  2812. X
  2813. X# define MANAGER_LOGIN \
  2814. X"You have logged in with manager privileges; you may not issue 'execute'\n\
  2815. Xrequests.\n\n"
  2816. X
  2817. X# define OWNER_LOGIN \
  2818. X"You have logged in with owner privileges; valid requests are:\n\n\
  2819. Xhelp [topic]\n\
  2820. Xset <list> [<option> <arg[s]>] -\n\
  2821. X\toption: mail, password, address, conceal\n\
  2822. X\targ for 'mail': ack/noack/postpone/digest\n\
  2823. X\targs for 'password': <current-password> <new-password>\n\
  2824. X\targs for 'address': <current-password> <new-address>\n\
  2825. X\targ for 'conceal': yes/no\n\
  2826. Xunsubscribe <list> - alias signoff\n\
  2827. Xrecipients <list> - alias review\n\
  2828. Xinformation <list>\n\
  2829. Xstatistics <list> [subscriber email address(es)] [-all]\n\
  2830. Xrun <list> [password cmd [args]]\n\
  2831. Xlists\n\
  2832. Xwhich\n\
  2833. Xindex [archive | path-to-archive] [/password] [-all]\n\
  2834. Xget <archive | path-to-archive> <file> [/password] [parts]\n\
  2835. Xview <archive | path-to-archive> <file> [/password] [parts]\n\
  2836. Xsearch <archive | path-to-archive> [/password] [-all] <pattern>\n\
  2837. Xrelease\n\
  2838. Xsystem <list> <password> <user-address> #user-request\n\
  2839. Xreports <list> <password>\n\
  2840. Xedit <list> <password> <file>\n\
  2841. X\tfile: subscribers/aliases/news/peers/ignored/info/welcome\n\
  2842. Xput <list> <password> <keyword> [args]\n\
  2843. X\tkeyword:alias/ignore/subscribers/aliases/news/peers/ignored/info/welcome\n\
  2844. X\targs:email address for alias/ignore\n\
  2845. Xapprove <list> <password> <tag>\n\
  2846. Xdiscard <list> <password> <tag>\n\n\
  2847. XYou may replace the administrative <password> with -\n\
  2848. XBuilt in commands are: quit/exit, ?/privileges, timeleft, binary, ascii\n\
  2849. XRequests may be continued on another line if they are terminated with &\\n\n\
  2850. XInput/output may be redirected with <, > and >>.\n\
  2851. XUNIX pipes are formed with the \"|\" symbol.\n\
  2852. XFor 'fax' requests, please send email.\n\
  2853. XUsing BINARY as default transfer mode.\n\n"
  2854. X
  2855. X# define SUBSCRIBER_LOGIN \
  2856. X"You have logged in with subscriber privileges; you may only issue the \
  2857. Xfollowing\nrequests:\n\n\
  2858. Xhelp [topic]\n\
  2859. Xset <list> [<option> <arg[s]>] -\n\
  2860. X\toption: mail, password, address, conceal\n\
  2861. X\targ for 'mail': ack/noack/postpone/digest\n\
  2862. X\targs for 'password': <current-password> <new-password>\n\
  2863. X\targs for 'address': <current-password> <new-address>\n\
  2864. X\targ for 'conceal': yes/no\n\
  2865. Xunsubscribe <list> - alias signoff\n\
  2866. Xrecipients <list> - alias review\n\
  2867. Xinformation <list>\n\
  2868. Xstatistics <list> [subscriber email address(es)] [-all]\n\
  2869. Xrun <list> [password cmd [args]]\n\
  2870. Xlists\n\
  2871. Xwhich\n\
  2872. Xindex [archive | path-to-archive] [/password] [-all]\n\
  2873. Xget <archive | path-to-archive> <file> [/password] [parts]\n\
  2874. Xview <archive | path-to-archive> <file> [/password] [parts]\n\
  2875. Xsearch <archive | path-to-archive> [/password] [-all] <pattern>\n\
  2876. Xrelease\n\n\
  2877. X<current-password> can be replaced with -\n\
  2878. XBuilt in commands are: quit/exit, ?/privileges, timeleft, binary, ascii\n\
  2879. XRequests may be continued on another line if they are terminated with &\\n\n\
  2880. XInput/output may be redirected with <, > and >>.\n\
  2881. XUNIX pipes are formed with the \"|\" symbol.\n\
  2882. XFor 'fax' requests, please send email.\n\
  2883. XUsing BINARY as default transfer mode.\n\n"
  2884. X
  2885. X# define GENERAL_LOGIN \
  2886. X"You have logged in as a casual user; you may only issue the following \
  2887. Xrequests:\n\n\
  2888. Xhelp [topic]\n\
  2889. Xrecipients <list> - alias review\n\
  2890. Xinformation <list>\n\
  2891. Xstatistics <list> [subscriber email address(es)] [-all]\n\
  2892. Xlists\n\
  2893. Xindex [archive | path-to-archive] [/password] [-all]\n\
  2894. Xget <archive | path-to-archive> <file> [/password] [parts]\n\
  2895. Xview <archive | path-to-archive> <file> [/password] [parts]\n\
  2896. Xsearch <archive | path-to-archive> [/password] [-all] <pattern>\n\
  2897. Xrelease\n\n\
  2898. XBuilt in commands are: quit/exit, ?/privileges, timeleft, binary, ascii\n\
  2899. XRequests may be continued on another line if they are terminated with &\\n\n\
  2900. XInput/output may be redirected with <, > and >>.\n\
  2901. XUNIX pipes are formed with the \"|\" symbol.\n\
  2902. XFor 'fax' requests, please send email.\n\
  2903. XUsing BINARY as default transfer mode.\n\n"
  2904. X
  2905. X# define SERVER_BUSY_ \
  2906. X"All interactive ListProcessor ports are busy. Please try again later.\n"
  2907. X
  2908. X# define GOOD_BYE \
  2909. X"ListProcessor closing connection.\n"
  2910. X
  2911. X# define CONN_TIMED_OUT \
  2912. X"Connection timed out.\n"
  2913. X
  2914. X# define SERVER_SHUTS_DOWN \
  2915. X"Server shutting down.\n"
  2916. X
  2917. X# define REMOTE_SYS_ERROR \
  2918. X"Remote system error.\n"
  2919. X
  2920. X# define MORE_INPUT \
  2921. X"[Enter text below, end with a '.' in a line by itself; do not forget to\n\
  2922. Xescape character sequences like | < >> >]\n"
  2923. X
  2924. X# define NULL_REDIRECT \
  2925. X"Invalid null output redirect\n"
  2926. X
  2927. X# define BINARY_XFER \
  2928. X"Transfer mode reset to binary\n"
  2929. X
  2930. X# define ASCII_XFER \
  2931. X"Transfer mode reset to ASCII\n"
  2932. X
  2933. X# define SERVICING_OTHER_CONN \
  2934. X"Server busy processing another request; please wait or hit ^C...\n"
  2935. X
  2936. X# define YOU_ARE_NEXT \
  2937. X"Processing your request...\n"
  2938. X
  2939. X# define CLIENT_LOST(exitcode) \
  2940. Xclose (msg_sock),\
  2941. X_exit (exitcode)  
  2942. X
  2943. X# define REPLY(msg_sock, code, bytes)\
  2944. X{\
  2945. X  sprintf (reply, "%d %d \n", code, (bytes));\
  2946. X  if (write_to_fd (msg_sock, reply, strlen (reply)) < 0)\
  2947. X    CLIENT_LOST (13);\
  2948. X}
  2949. X
  2950. X# define REPLY_ERROR(msg_sock, code, bytes, __msg__)\
  2951. X{\
  2952. X  sprintf (reply, "%d %d \n%s", code, (bytes), __msg__);\
  2953. X  if (write_to_fd (msg_sock, reply, strlen (reply)) < 0)\
  2954. X    CLIENT_LOST (13);\
  2955. X}
  2956. X# define REPLY_FILE(msg_sock, code, bytes, file)\
  2957. X{\
  2958. X  sprintf (reply, "%d %d %s\n", code, (bytes), file);\
  2959. X  if (write_to_fd (msg_sock, reply, strlen (reply)) < 0)\
  2960. X    CLIENT_LOST (13);\
  2961. X}
  2962. X
  2963. X# define CLOSE_CLIENT(msg_sock) \
  2964. X  if (msg_sock >= 0) {\
  2965. X    REPLY (msg_sock, CONN_CLOSED, strlen (GOOD_BYE));\
  2966. X    write_to_fd (msg_sock, GOOD_BYE, strlen (GOOD_BYE));\
  2967. X    close (msg_sock);\
  2968. X  }
  2969. X
  2970. X# define CANNOT_CONNECT(__msg__, __code__, __reply__) \
  2971. X{\
  2972. X  sprintf (msg, "%d %d %s %d %d\n%d %d \n%s", CONNECT, conn_duration,\
  2973. X       version, strlen (PROMPT), strlen (CONT_PROMPT), __code__,\
  2974. X       strlen (__reply__), __reply__);\
  2975. X  write_to_fd (msg_sock, msg, strlen (msg));\
  2976. X  close (msg_sock);\
  2977. X  report_progress (report, __msg__, TRUE);\
  2978. X}
  2979. X
  2980. X# define GET_LOGIN(buf) \
  2981. X{\
  2982. X  ch = EOS;\
  2983. X  bytes_read = 0;\
  2984. X  while (ch != '\n' && bytes_read < MAX_LINE) {\
  2985. X    if (read (msg_sock, &ch, 1) <= 0 || ch == EOF)\
  2986. X      goto abort;\
  2987. X    if (time (0) - time_started > conn_duration)\
  2988. X      close_connection (TIMEOUT_SIG);\
  2989. X    buf [bytes_read++] = ((ch < ' ' && ch != '\t' && ch != '\n' && ch != '\r')\
  2990. X|| (ch == (char) 127) ? ((char) 0) : ch);\
  2991. X  }\
  2992. X  buf [bytes_read] = EOS;\
  2993. X  clean_request (buf);\
  2994. X  l = 0;\
  2995. X  while (buf [l] != EOS) {\
  2996. X    if (buf [l] == '\n' || buf [l] == '\r')\
  2997. X      buf [l] = EOS;\
  2998. X    ++l;\
  2999. X  }\
  3000. X}
  3001. X
  3002. X# define SET_NONBLOCKING(__func__) \
  3003. X  if (fcntl (msg_sock, F_SETFL, \
  3004. X         (mask = fcntl (msg_sock, F_GETFL, 0)) | O_NDELAY) < 0) \
  3005. X    report_progress (report,\
  3006. X             tsprintf ("\n%s(): fcntl() failed: errno %d",\
  3007. X                   __func__, errno), TRUE);
  3008. X
  3009. X# define SET_BLOCKING(__func__) \
  3010. X  if (fcntl (msg_sock, F_SETFL, mask) < 0) \
  3011. X    report_progress (report,\
  3012. X             tsprintf ("\n%s(): fcntl() failed: errno %d",\
  3013. X                   __func__, errno), TRUE);
  3014. X
  3015. X# define SEND_OOB_BYTE \
  3016. X{ int value;\
  3017. X  do {\
  3018. X    errno = 0;\
  3019. X    value = send (msg_sock, "#", 1, MSG_OOB);\
  3020. X  } while (value < 0 && errno == ENOBUFS);\
  3021. X  if (value < 0 && errno != ENOBUFS)\
  3022. X     report_progress (report,\
  3023. X              tsprintf ("\nprocess_live_request(): \
  3024. Xsend() failed: errno %d", errno), TRUE);\
  3025. X}
  3026. X
  3027. X# define SEND_MSG \
  3028. X{ int value;\
  3029. X  do {\
  3030. X    errno = 0;\
  3031. X    value = send (msg_sock, urgmsg, MSGLEN, NULL);\
  3032. X  } while (value < 0 && errno == ENOBUFS);\
  3033. X  if (value < 0 && errno != ENOBUFS)\
  3034. X    report_progress (report,\
  3035. X             tsprintf ("\nprocess_live_request(): \
  3036. Xsend() failed: errno %d", errno), TRUE);\
  3037. X}
  3038. X
  3039. X# define CHECK_CRITICAL_SECTION(__func__, msg_sock, __mask__) \
  3040. X{\
  3041. X  char msg [256], ch;\
  3042. X  long int time_started, delay = 0, value;\
  3043. X\
  3044. X  time (&time_started);\
  3045. X  while (interactive && msg_sock && (value = semctl (sid, 0, GETVAL)) >= 0 &&\
  3046. X     (value & (__mask__))) {\
  3047. X    REPLY (msg_sock, MESSAGE, strlen (SERVICING_OTHER_CONN));\
  3048. X    write_to_fd (msg_sock, SERVICING_OTHER_CONN,strlen (SERVICING_OTHER_CONN));\
  3049. X    --time_started;\
  3050. X    while (((time (0) - time_started) % 10) && (value = semctl (sid, 0, GETVAL)) >= 0 &&\
  3051. X       (value & (__mask__))) {\
  3052. X      SET_NONBLOCKING (__func__);\
  3053. X      if ((value = recv (msg_sock, &ch, 1, MSG_OOB)) > 0)\
  3054. X    if (ch == '\03') {\
  3055. X      sprintf (urgmsg, "%08d", 0);\
  3056. X      SET_BLOCKING (__func__);\
  3057. X      SEND_OOB_BYTE;\
  3058. X      SEND_MSG;\
  3059. X      already_aborted = TRUE;\
  3060. X      REPLY (msg_sock, OK, strlen (PROMPT));\
  3061. X      goto Skip;\
  3062. X    }\
  3063. X    else\
  3064. X      report_progress (report,\
  3065. X                 tsprintf ("\n%s(): \
  3066. Xrecv(): unexpected char %c", __func__, ch), TRUE);\
  3067. X      else if (value < 0 && errno && errno != EWOULDBLOCK &&\
  3068. X           errno != EAGAIN && errno != EINTR && errno != EINVAL)\
  3069. X    report_progress (report,\
  3070. X             tsprintf ("\n%s(): \
  3071. Xrecv() failed: errno %d", __func__, errno), TRUE);\
  3072. X      SET_BLOCKING (__func__);\
  3073. X    }\
  3074. X    delay = 1;\
  3075. X  }\
  3076. X  if (delay) {\
  3077. X    REPLY (msg_sock, MESSAGE, strlen (YOU_ARE_NEXT));\
  3078. X    write_to_fd (msg_sock, YOU_ARE_NEXT, strlen (YOU_ARE_NEXT));\
  3079. X  }\
  3080. X}
  3081. X
  3082. Xtypedef struct {
  3083. X  long int pid,            /* Client pid */
  3084. X         time,        /* Time connection established */
  3085. X         connid;        /* Client id */
  3086. X  char name [MAX_LINE];        /* Remote host's IP address or name */
  3087. X} CLIENT;
  3088. X
  3089. XCLIENT clients [MAX_CONNECTIONS];
  3090. X  
  3091. Xlong int chpid, nforks, sock_fd, msg_sock;
  3092. Xint sid, connid, conn_duration;
  3093. Xstruct passwd *pwentry;
  3094. Xchar requests_file [MAX_LINE], mailforwardf [MAX_LINE];
  3095. Xchar urgmsg [MSGLEN + 1];
  3096. X
  3097. XBOOLEAN chdied = FALSE;
  3098. X#endif
  3099. *-*-END-of-src/serverd.h-*-*
  3100. echo x - src/start.h
  3101. sed 's/^X//' >src/start.h <<'*-*-END-of-src/start.h-*-*'
  3102. X/*
  3103. X  AGREEMENT: This software can be used and distributed freely only as a
  3104. X  whole and not in parts, as long as you do not remove or alter the author
  3105. X  and copyright notices in the file defs.h; this notices are #define'd in
  3106. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3107. X  provided for your personal use, you may not alter the functions
  3108. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3109. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3110. X  any changes you may have made. No part of the source code bearing a
  3111. X  copyright notice can be included in commercial software systems without
  3112. X  written permission by the author.
  3113. X  By using this software you are bound by this agreement.
  3114. X  This software comes with no warranties and cannot be sold for profit.
  3115. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3116. X  files when distributing this software.
  3117. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3118. X  Use, duplication or disclosure by the Federal Government is subject to the
  3119. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3120. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3121. X
  3122. X  Below are the #define's pertinent to start.c
  3123. X
  3124. X  Preserve any quotes that appear below; change only path names.
  3125. X
  3126. X  ALWAYS SPECIFY ABSOLUTE PATHS.
  3127. X
  3128. X*/
  3129. X
  3130. X#ifdef __STDC__
  3131. X# include "ansi/start.h"
  3132. X#else
  3133. X# include "nonansi/start.h"
  3134. X#endif
  3135. X
  3136. X#ifdef __NeXT__
  3137. X# include "next.h"
  3138. X#endif
  3139. X
  3140. X#define MODERATED_MAIL_FILE "moderated"
  3141. X
  3142. X#define START_ABORT \
  3143. X  fprintf (stderr, "### start aborted; system not started. ###\n"),\
  3144. X  exit (1);
  3145. X
  3146. X#define DEFAULT_ALIASES \
  3147. X"^@.*:(.*)@(.*\\..*) \\1@\\2"
  3148. X
  3149. Xchar    report_list_accf [MAX_LINE];
  3150. Xchar    *pids [] = { PID_LIST, PID_SERVERD, PID_PQUEUE, PID_QUEUED, NULL };
  3151. Xchar    *mask;
  3152. XBOOLEAN tty_echo = TRUE;
  3153. XFILE    *report  = NULL;
  3154. Xint    sid = -1;
  3155. *-*-END-of-src/start.h-*-*
  3156. echo x - src/struct.h
  3157. sed 's/^X//' >src/struct.h <<'*-*-END-of-src/struct.h-*-*'
  3158. X/*
  3159. X  AGREEMENT: This software can be used and distributed freely only as a
  3160. X  whole and not in parts, as long as you do not remove or alter the author
  3161. X  and copyright notices in the file defs.h; this notices are #define'd in
  3162. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3163. X  provided for your personal use, you may not alter the functions
  3164. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3165. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3166. X  any changes you may have made. No part of the source code bearing a
  3167. X  copyright notice can be included in commercial software systems without
  3168. X  written permission by the author.
  3169. X  By using this software you are bound by this agreement.
  3170. X  This software comes with no warranties and cannot be sold for profit.
  3171. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3172. X  files when distributing this software.
  3173. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3174. X  Use, duplication or disclosure by the Federal Government is subject to the
  3175. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3176. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3177. X*/
  3178. X
  3179. Xtypedef struct _prec_header {    /* Header lines to be saved */
  3180. X  char   *line;
  3181. X  struct _prec_header *next;
  3182. X} PRECIOUS_HEADER;
  3183. X
  3184. Xtypedef struct _unix_cmds {
  3185. X  char password [MAX_LINE],    /* Password for this  command */
  3186. X       name [MAX_LINE],        /* Name of the  command users may execute */
  3187. X       *cmd,            /* Actual  command to execute */
  3188. X       *comment;        /* Syntax message, or any other message */
  3189. X  struct _unix_cmds *next;    /* Pointer to next structure */
  3190. X} _CMDS;
  3191. X
  3192. Xtypedef struct {
  3193. X  char set_values [MAX_SET_OPTIONS][MAX_LINE];
  3194. X} DEFAULTS;
  3195. X
  3196. Xtypedef struct {
  3197. X  struct {
  3198. X    char alias [MAX_LINE],    /* As it appears in the aliases file */
  3199. X     comment [MAX_LINE],    /* Comment: line in the outgoing mail message */
  3200. X         address [MAX_LINE],    /* Full email address of the list */
  3201. X     owner [MAX_LINE],    /* Email address of the list's owner */
  3202. X     password [MAX_LINE],    /* Password that owner uses */
  3203. X         cmdoptions [MAX_LINE],    /* List-specific command line options */
  3204. X     arch_dir [MAX_LINE],    /* Directory to put archive files in */
  3205. X     farch_dir [MAX_LINE],    /*     " in which to record archive in DIR */
  3206. X     arch_spec [MAX_LINE],    /* Specifies name of archive files */
  3207. X     arch_pass [MAX_LINE];    /* Password (if any) for the archive */
  3208. X    int     owner_prefs,        /* Owner preferences */
  3209. X     disabled_commands,    /* Mask of disabled commands for this list */
  3210. X     digest_lines,          /* Max number of lines in digest */
  3211. X     digest_hours,          /* Send out digest every so many hours */
  3212. X     ncmds,            /* Count of  commands that may be executed*/
  3213. X     max_messages,        /* Maximum number of messages per day */
  3214. X     options;        /* Mask of options: autosub, conceal, archive */
  3215. X    PRECIOUS_HEADER *header;    /* Precious header lines */
  3216. X    _CMDS *unix_cmds;    /*  commands that users may execute */
  3217. X    DEFAULTS defaults;        /* Default list settings */
  3218. X  } lists [MAX_LISTS];        /* Structure for each list */
  3219. X  struct {
  3220. X    char address [MAX_LINE],    /* Full email address of the server */
  3221. X     comment [MAX_LINE],    /* Comment: line in the outgoing mail message */
  3222. X         cmdoptions [MAX_LINE],    /* ListProcessor-specific command line options */
  3223. X     password [MAX_LINE];    /* For 'shutdown', 'restart' and 'execute' */
  3224. X    int manager_prefs;        /* System manager preferences */
  3225. X  } server;            /* Structure for the server */
  3226. X  struct {
  3227. X    char *method,        /* Mail method to use */
  3228. X     env_var [MAX_LINE],    /* Environment variable to use */
  3229. X     mail_prog [MAX_LINE],    /* Which mail program to use */
  3230. X     precedence [MAX_LINE];    /* Which mail precedence to use */
  3231. X  } mail;            /* Mail method structure */
  3232. X  struct {
  3233. X    long int msg,        /* Maximum message limit in bytes */
  3234. X         files;        /* Maximum file size before auto splitting */
  3235. X  } limits;            /* Various limits are defined here */
  3236. X  struct {
  3237. X    unsigned int start,
  3238. X         stop;
  3239. X  } batch;            /* When to batch requests */
  3240. X  struct {
  3241. X    char prog [MAX_LINE],    /* Faxing program */
  3242. X     fax_no [MAX_LINE];    /* Fax number */
  3243. X  } fax;
  3244. X  char serverd_cmdoptions [MAX_LINE],/* Command line options */
  3245. X       manager [MAX_LINE],    /* Manager of the system */
  3246. X       arg [MAX_LINE],        /* Temporary storage */
  3247. X       organization [MAX_LINE]; /* Organization's name */
  3248. X       int users,        /* Used by listproc when -r is given */
  3249. X       frequency;        /* How often to read mail */
  3250. X  long int options;        /* Various flags: BSD_PS, USE_TELNET, etc. */
  3251. X} SYS;
  3252. X
  3253. Xtypedef void (*FUNC)();
  3254. X
  3255. Xtypedef struct {
  3256. X  char *name;
  3257. X  long int mask;
  3258. X  FUNC func;
  3259. X} COMMANDS;            /* Structure for requests */
  3260. X
  3261. Xtypedef struct remote {
  3262. X  char alias [MAX_LINE],
  3263. X       address [MAX_LINE],
  3264. X       comment [MAX_LINE],
  3265. X       listproc [MAX_LINE],
  3266. X       inet_addr [MAX_LINE];
  3267. X  int  port;
  3268. X  struct remote *next;
  3269. X} REMOTE;            /* Structure for remote lists */
  3270. *-*-END-of-src/struct.h-*-*
  3271. echo x - src/sysmail.h
  3272. sed 's/^X//' >src/sysmail.h <<'*-*-END-of-src/sysmail.h-*-*'
  3273. X/*
  3274. X  AGREEMENT: This software can be used and distributed freely only as a
  3275. X  whole and not in parts, as long as you do not remove or alter the author
  3276. X  and copyright notices in the file defs.h; this notices are #define'd in
  3277. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3278. X  provided for your personal use, you may not alter the functions
  3279. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3280. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3281. X  any changes you may have made. No part of the source code bearing a
  3282. X  copyright notice can be included in commercial software systems without
  3283. X  written permission by the author.
  3284. X  By using this software you are bound by this agreement.
  3285. X  This software comes with no warranties and cannot be sold for profit.
  3286. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3287. X  files when distributing this software.
  3288. X  COPYRIGHT: Copyright (c) 1991/92, Anastasios C. Kotsikonas
  3289. X  Use, duplication or disclosure by the Federal Government is subject to the
  3290. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3291. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3292. X*/
  3293. X
  3294. X#ifdef __STDC__
  3295. X#include "ansi/sysmail.h"
  3296. X#else
  3297. X#include "nonansi/sysmail.h"
  3298. X#endif
  3299. X
  3300. X#include <errno.h>
  3301. X
  3302. X#define PORT          25    /* sendmail port */
  3303. X#define TIMEOUT           600    /* 10 mins timeout connecting to sendmail */
  3304. X#define CONN_TIMEOUT      -1
  3305. X#define MAX_CALLS      1    /* if > 1, retry delivery that many times */
  3306. X#ifndef SENDMAIL_HOST
  3307. X#define    SENDMAIL_HOST      "localhost"
  3308. X#endif
  3309. X
  3310. X/* List of SMTP commands recognized */
  3311. X
  3312. X#define ACKNOWLEDGE      220
  3313. X#define CLOSE_CONNECTION  221
  3314. X#define OK                250
  3315. X#define WILL_FORWARD      251
  3316. X#define DATA          354
  3317. X#define SERVICE_UNAVAIL      421
  3318. X#define PERMISSION_DENIED 450
  3319. X#define HOST_ABORTED      451
  3320. X#define DISK_FULL      452
  3321. X#define NOT_RECOGNIZED    500
  3322. X#define SYNTAX_ERROR      501
  3323. X#define CMD_NOT_IMPL      502
  3324. X#define BAD_SEQUENCE      503
  3325. X#define PARAM_NOT_IMPL    504
  3326. X#define USER_UNKNOWN      550
  3327. X#define USER_NOT_LOCAL    551
  3328. X#define TOO_MUCH_DATA      552
  3329. X#define USER_AMBIGUOUS    553
  3330. X#define TRANS_FAILED        554
  3331. X#define END_OF_TEXT      ".\n"
  3332. X
  3333. X#define CLOSEF \
  3334. X  fclose (msg),\
  3335. X  close (sock_fd)
  3336. X
  3337. X#define NOTIFY_MANAGER(error) \
  3338. X  if (sys.options & BSD_MAIL)\
  3339. X    syscom ("echo '%s' | %s -s 'Error during message delivery: ' %s &",\
  3340. X        error, UCB_MAIL, sys.manager)
  3341. X
  3342. X#define WARN_MANAGER_AND_OWNER(warning) \
  3343. X  if (sys.options & BSD_MAIL) {\
  3344. X    syscom ("echo '%s' | %s -s '%s: Warning during message delivery: ' %s &",\
  3345. X        warning, UCB_MAIL,\
  3346. X(listid < 0 ? "LISTPROC" : sys.lists[listid].alias), sys.manager);\
  3347. X    if (listid >= 0 && strcmp (sys.manager, sys.lists[listid].owner))\
  3348. X      syscom ("echo '%s' | %s -s '%s: Warning during message delivery: ' %s &",\
  3349. X            warning, UCB_MAIL,\
  3350. X(listid < 0 ? "LISTPROC" : sys.lists[listid].alias), sys.lists[listid].owner);\
  3351. X  }
  3352. X
  3353. X#define ABORT_CONNECTION \
  3354. X  if ((int) write (sock_fd, "QUIT\n", 5) < 5)\
  3355. X    report_progress (report, "_sysmail(): WARNING: Error writing to \
  3356. Xsocket, while closing connection", TRUE);\
  3357. X  if (debug)\
  3358. X    fprintf (sent, "QUIT\n[ transaction aborted ]\n"),\
  3359. X    fflush (sent);\
  3360. X  cmd = server_response (sock_fd);
  3361. X
  3362. X#define CHECK_SERVER_RESPONSE(cmd, arg, cont)\
  3363. X  if (cmd != OK && cmd != arg) {\
  3364. X    char error [1024];\
  3365. X    if (cmd == SYNTAX_ERROR || cmd == TRANS_FAILED ||\
  3366. X        cmd == NOT_RECOGNIZED) {\
  3367. X      sprintf (error, "_sysmail(): Command: %snot recognized by sendmail.\
  3368. X\n%s\nCould not deliver mail", buf, message);\
  3369. X      report_progress (report, error, TRUE);\
  3370. X      NOTIFY_MANAGER (error);\
  3371. X      ABORT_CONNECTION;\
  3372. X      queue = TRUE;\
  3373. X      goto abort;\
  3374. X    }\
  3375. X    else if (cmd == CMD_NOT_IMPL || cmd == PARAM_NOT_IMPL) {\
  3376. X      sprintf (error, "_sysmail(): Command: %snot implemeted.\n%s\n\
  3377. XCould not deliver mail", buf, message);\
  3378. X      report_progress (report, error, TRUE);\
  3379. X      NOTIFY_MANAGER (error);\
  3380. X      ABORT_CONNECTION;\
  3381. X      queue = TRUE;\
  3382. X      goto abort;\
  3383. X    }\
  3384. X    else if (cmd == BAD_SEQUENCE) {\
  3385. X      sprintf (error, "_sysmail(): Command: %sissued too soon.\
  3386. X\n%s\nCould not deliver mail", buf, message);\
  3387. X      report_progress (report, error, TRUE);\
  3388. X      NOTIFY_MANAGER (error);\
  3389. X      ABORT_CONNECTION;\
  3390. X      queue = TRUE;\
  3391. X      goto abort;\
  3392. X    }\
  3393. X    else if (cmd == SERVICE_UNAVAIL || cmd == HOST_ABORTED) {\
  3394. X      sprintf (error, "_sysmail(): Service unavailable.\
  3395. X\n%s\nCould not deliver mail", message);\
  3396. X      report_progress (report, error, TRUE);\
  3397. X      NOTIFY_MANAGER (error);\
  3398. X      ABORT_CONNECTION;\
  3399. X      queue = TRUE;\
  3400. X      goto abort;\
  3401. X    }\
  3402. X    else if (cmd == DISK_FULL) {\
  3403. X      sprintf (error, "_sysmail(): File system full.\n%s\nCould not \
  3404. Xdeliver mail", message);\
  3405. X      report_progress (report, error, TRUE);\
  3406. X      NOTIFY_MANAGER (error);\
  3407. X      ABORT_CONNECTION;\
  3408. X      queue = TRUE;\
  3409. X      goto abort;\
  3410. X    }\
  3411. X    else if (cmd == TOO_MUCH_DATA) {\
  3412. X      sprintf (error, "_sysmail(): Too many recipients or message \
  3413. Xtoo long.\n%s\nCould not deliver mail", message);\
  3414. X      report_progress (report, error, TRUE);\
  3415. X      NOTIFY_MANAGER (error);\
  3416. X      ABORT_CONNECTION;\
  3417. X      queue = TRUE;\
  3418. X      goto abort;\
  3419. X    }\
  3420. X    else if (cmd == CONN_TIMEOUT) {\
  3421. X      sprintf (error, "_sysmail(): Connection timed out with %s. \
  3422. XCould not deliver mail", SENDMAIL_HOST);\
  3423. X      report_progress (report, error, TRUE);\
  3424. X      NOTIFY_MANAGER (error);\
  3425. X      queue = TRUE;\
  3426. X      goto abort;\
  3427. X    }\
  3428. X    else if (cmd == USER_UNKNOWN) {\
  3429. X      sprintf (error, "_sysmail(): Address: %snot recognized.\n%s\nMessage \
  3430. Xnot delivered to this recipient", buf, message);\
  3431. X      report_progress (report, error, TRUE);\
  3432. X      WARN_MANAGER_AND_OWNER (error);\
  3433. X      cont;\
  3434. X    }\
  3435. X    else if (cmd == USER_NOT_LOCAL) {\
  3436. X      sprintf (error, "_sysmail(): Address: %snot local; %s", buf, message);\
  3437. X      report_progress (report, error, TRUE);\
  3438. X      WARN_MANAGER_AND_OWNER (error);\
  3439. X      cont;\
  3440. X    }\
  3441. X    else if (cmd == USER_AMBIGUOUS) {\
  3442. X      sprintf (error, "_sysmail(): Address ambiguous: %s%s\nMessage not \
  3443. Xdelivered to this address", buf, message);\
  3444. X      report_progress (report, error, TRUE);\
  3445. X      WARN_MANAGER_AND_OWNER (error);\
  3446. X      cont;\
  3447. X    }\
  3448. X    else if (cmd == PERMISSION_DENIED) {\
  3449. X      sprintf (error, "_sysmail(): Permission denied for address %s%s\n\
  3450. XMessage not delivered to this recipient", buf, message);\
  3451. X      report_progress (report, error, TRUE);\
  3452. X      WARN_MANAGER_AND_OWNER (error);\
  3453. X      cont;\
  3454. X    }\
  3455. X    else if (cmd == WILL_FORWARD) {\
  3456. X      sprintf (error, "_sysmail(): Address: %snot local; %s", buf, message);\
  3457. X      report_progress (report, error, TRUE);\
  3458. X      WARN_MANAGER_AND_OWNER (error);\
  3459. X      cont;\
  3460. X    }\
  3461. X    else {\
  3462. X      sprintf (error, "_sysmail(): ERROR: Return value %d for command: %s%s\n\
  3463. XPlease notify tasos@cs.bu.edu", cmd, buf, message);\
  3464. X      report_progress (report, error, TRUE);\
  3465. X      NOTIFY_MANAGER (error);\
  3466. X      if (call < MAX_CALLS)\
  3467. X        CLOSEF,\
  3468. X        sleep (60),\
  3469. X        _sysmail (file, call + 1);\
  3470. X      report_progress (report, "_sysmail(): ERROR: Could not deliver mail", \
  3471. XTRUE);\
  3472. X      CLOSEF,\
  3473. X      gexit (10);\
  3474. X    }\
  3475. X  }
  3476. X
  3477. X#define WRITE_TO_SOCKET(sock_fd, buf)\
  3478. X{ char bufcopy [1024];\
  3479. X  strcpy (bufcopy, buf);\
  3480. X  bytes_to_write = strlen (bufcopy);\
  3481. X  errno = 0;\
  3482. X  while ((bytes_written = write (sock_fd, bufcopy, strlen (bufcopy))) <\
  3483. X         bytes_to_write) {\
  3484. X    if (errno && errno != EWOULDBLOCK && errno != EAGAIN) {\
  3485. X      char error [MAX_LINE];\
  3486. X      switch (errno) {\
  3487. X    case EBADF: sprintf (error, "_sysmail(): Bad file number"); break;\
  3488. X    case EFAULT: sprintf (error, "_sysmail(): Bad address"); break;\
  3489. X    case EFBIG: sprintf (error, "_sysmail(): File limit reached"); break;\
  3490. X    case EINTR: sprintf (error, "_sysmail(): Received interrupt signal");\
  3491. X            break;\
  3492. X    case EINVAL: sprintf (error, "_sysmail(): Negative seek pointer");\
  3493. X             break;\
  3494. X    case EIO: sprintf (error, "_sysmail(): I/O error"); break;\
  3495. X     case ENOSPC: sprintf (error, "_sysmail(): No space left on device");\
  3496. X             break;\
  3497. X    case ENXIO: sprintf (error, "_sysmail(): No such device or address");\
  3498. X            break;\
  3499. X    case ERANGE: sprintf (error, "_sysmail(): Bytes to write (%d) out of \
  3500. Xrange", bytes_to_write);\
  3501. X             break;\
  3502. X    default: sprintf (error, "_sysmail(): Error number %d", errno);\
  3503. X      }\
  3504. X      report_progress (report, error, TRUE);\
  3505. X      queue = TRUE;\
  3506. X      goto abort;\
  3507. X    }\
  3508. X    if (debug) {\
  3509. X      for (i = 0; i < bytes_written; fprintf (sent, "%c", bufcopy [i++]));\
  3510. X      fflush (sent);\
  3511. X    }\
  3512. X    if (bytes_written > 0)\
  3513. X      bytes_to_write -= bytes_written;\
  3514. X    if (bytes_written > 0)\
  3515. X      sprintf (bufcopy, "%s", bufcopy + bytes_written);\
  3516. X    errno = 0;\
  3517. X  }\
  3518. X  if (debug)\
  3519. X    fprintf (sent, "%s", bufcopy),\
  3520. X    fflush (sent);\
  3521. X}
  3522. X
  3523. X#ifdef USE_CARRIAGE_RETURN_LINEFEED
  3524. X# define CONVERT(__s__) \
  3525. X{ \
  3526. X  char *r = strrchr (__s__, '\n');\
  3527. X  if (r) strcpy (r, "\r\n");\
  3528. X}
  3529. X#else
  3530. X# define CONVERT(__s__)
  3531. X#endif
  3532. X
  3533. X#define PROTOCOL(arg) \
  3534. X  while (!feof (msg) && cmd != arg) {\
  3535. X    RESET (buf);\
  3536. X    fgets (buf, MAX_LINE - 2, msg);\
  3537. X    CONVERT (buf);\
  3538. X    WRITE_TO_SOCKET (sock_fd, buf);\
  3539. X    if ((cmd = server_response (sock_fd)) == CONN_TIMEOUT) {\
  3540. X      queue = TRUE;\
  3541. X      goto abort;\
  3542. X    }\
  3543. X    CHECK_SERVER_RESPONSE (cmd, arg, continue);\
  3544. X  }
  3545. X
  3546. Xstatic char message [1024];
  3547. Xstatic FILE *sent, *received;
  3548. Xstatic BOOLEAN queue;
  3549. *-*-END-of-src/sysmail.h-*-*
  3550. echo x - src/ansi/catmail.h
  3551. sed 's/^X//' >src/ansi/catmail.h <<'*-*-END-of-src/ansi/catmail.h-*-*'
  3552. X#define LOST_REQUESTS        PATH "/lost+found"
  3553. X#define TAG_IDF            PATH "/.tag.id"
  3554. X#define    CATMAIL_TMP        PATH "/.catmail.tmp"
  3555. *-*-END-of-src/ansi/catmail.h-*-*
  3556. echo x - src/ansi/defs.h
  3557. sed 's/^X//' >src/ansi/defs.h <<'*-*-END-of-src/ansi/defs.h-*-*'
  3558. X/*
  3559. X  AGREEMENT: This software can be used and distributed freely only as a
  3560. X  whole and not in parts, as long as you do not remove or alter the author
  3561. X  and copyright notices in the file defs.h; this notices are #define'd in
  3562. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3563. X  provided for your personal use, you may not alter the functions
  3564. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3565. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3566. X  any changes you may have made. No part of the source code bearing a
  3567. X  copyright notice can be included in commercial software systems without
  3568. X  written permission by the author.
  3569. X  By using this software you are bound by this agreement.
  3570. X  This software comes with no warranties and cannot be sold for profit.
  3571. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3572. X  files when distributing this software.
  3573. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3574. X  Use, duplication or disclosure by the Federal Government is subject to the
  3575. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3576. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3577. X*/
  3578. X
  3579. X#define PATH              "/usr/server"
  3580. X#define WARNING           PATH "/.warning"
  3581. X#define REPORT_SERVER     PATH "/.report.server"
  3582. X#define REPORT_SERVERD    PATH "/.report.daemon"
  3583. X#define REPORT_PQUEUE     PATH "/.report.pqueue"
  3584. X#define REPORT_CATMAIL      PATH "/.report.catmai"
  3585. X#define CONFIG            PATH "/config"
  3586. X#define LIST              PATH "/list -1 -L "
  3587. X#define SERVER            PATH "/listproc -1 "
  3588. X#define SERVER_MAIL_FILE  PATH "/requests"
  3589. X#define BATCH_FILE      PATH "/batch"
  3590. X#define SERVERD           PATH "/serverd"
  3591. X#define PQUEUE            PATH "/pqueue"
  3592. X#define START             PATH "/start"
  3593. X#define OWNERSF           PATH "/owners"
  3594. X#define ALIASESF      PATH "/.aliases"
  3595. X#define SERVERD_LOCK_FILE PATH "/.lock.serverd"
  3596. X#define PQUEUE_LOCK_FILE  PATH "/.lock.pqueue"
  3597. X#define PID_PQUEUE        PATH "/.pid.pqueue"
  3598. X#define PID_SERVERD       PATH "/.pid.daemon"
  3599. X#define PID_SERVER        PATH "/.pid.server"
  3600. X#define PID_LIST          PATH "/.pid.list"
  3601. X#define PID_QUEUED      PATH "/.pid.queued"
  3602. X#define MAILFORWARD       PATH "/.mailforward"
  3603. X#define ULISTPROCESSOR_REPLY      PATH "/.reply"
  3604. X#define ARCHIVE_DIR       PATH "/archives"
  3605. X#define OLD_SUBSCRIBERS   PATH "/.oldsubscriber"
  3606. X#define OLD_ALIASES      PATH "/.oldaliases"
  3607. X#define NEW_SUBSCRIBERS   PATH "/.newsubscriber"
  3608. X#define NEW_ALIASES      PATH "/.newaliases"
  3609. X#define    TMP_LIVE      PATH "/.live"
  3610. *-*-END-of-src/ansi/defs.h-*-*
  3611. echo x - src/ansi/listproc.h
  3612. sed 's/^X//' >src/ansi/listproc.h <<'*-*-END-of-src/ansi/listproc.h-*-*'
  3613. X/*
  3614. X  AGREEMENT: This software can be used and distributed freely only as a
  3615. X  whole and not in parts, as long as you do not remove or alter the author
  3616. X  and copyright notices in the file defs.h; this notices are #define'd in
  3617. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3618. X  provided for your personal use, you may not alter the functions
  3619. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3620. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3621. X  any changes you may have made. No part of the source code bearing a
  3622. X  copyright notice can be included in commercial software systems without
  3623. X  written permission by the author.
  3624. X  By using this software you are bound by this agreement.
  3625. X  This software comes with no warranties and cannot be sold for profit.
  3626. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3627. X  files when distributing this software.
  3628. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3629. X  Use, duplication or disclosure by the Federal Government is subject to the
  3630. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3631. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3632. X*/
  3633. X
  3634. X#define MAIL_COPY         PATH "/.messages"
  3635. X#define MSG_NO            PATH "/.msgno"
  3636. X#define AWK_PROG          PATH "/.awk"
  3637. X#define STATS_PROG        PATH "/.stats"
  3638. X#define SERVER_MBOX       PATH "/mbox"
  3639. X#define HELP_TOPICS      PATH "/help/TOPICS"
  3640. X#define STDOUT          PATH "/stdout"
  3641. X#define STDERR          PATH "/stderr"
  3642. X#define SETUP_MESSAGE_IDSF sprintf (message_idsf, "%s/%s", PATH, MESSAGE_IDS_F)
  3643. X#define EXEC_STATS \
  3644. X  syscom ("%s %s %s %s %s %s", STATS_PROG, PATH, subscribersf,\
  3645. X          headersf, mailforwardf, params)
  3646. X
  3647. X#define REARRANGE_SUBSCRIBERS \
  3648. X  syscom ("%s/rev < %s | awk '{print $NF \"\\t\" $0}' | sort | \
  3649. Xsed 's/^.*\t//' | %s/rev > %s/sub.%s", PATH, subscribersf,\
  3650. X      PATH, PATH, sys.lists[listid].alias);\
  3651. X  mv (tsprintf ("%s/sub.%s", PATH, sys.lists[listid].alias), subscribersf)
  3652. X
  3653. X#define CAT_FILE \
  3654. X  syscom ("%s %s | %s/fwin -n -o %ld -b %ld | sed -e 's/^From />From /' | \
  3655. Xsed -e 's/^\\.$/\\\\./' >> %s", \
  3656. X      (compressed_source ? "zcat" : "cat"), fullname, PATH, offset,\
  3657. X      nbytes, mailforwardf)
  3658. *-*-END-of-src/ansi/listproc.h-*-*
  3659. echo x - src/ansi/misc.h
  3660. sed 's/^X//' >src/ansi/misc.h <<'*-*-END-of-src/ansi/misc.h-*-*'
  3661. X/*
  3662. X  AGREEMENT: This software can be used and distributed freely only as a
  3663. X  whole and not in parts, as long as you do not remove or alter the author
  3664. X  and copyright notices in the file defs.h; this notices are #define'd in
  3665. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3666. X  provided for your personal use, you may not alter the functions
  3667. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3668. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3669. X  any changes you may have made. No part of the source code bearing a
  3670. X  copyright notice can be included in commercial software systems without
  3671. X  written permission by the author.
  3672. X  By using this software you are bound by this agreement.
  3673. X  This software comes with no warranties and cannot be sold for profit.
  3674. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3675. X  files when distributing this software.
  3676. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3677. X  Use, duplication or disclosure by the Federal Government is subject to the
  3678. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3679. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3680. X*/
  3681. X
  3682. X#define SETUP_STRING sprintf (s, "%s/lists/%s/%s", PATH, alias, filename)
  3683. X#define SETUP_IGNOREDF sprintf (server_ignoredf, "%s/%s", PATH, IGNORED)
  3684. *-*-END-of-src/ansi/misc.h-*-*
  3685. echo x - src/ansi/serverd.h
  3686. sed 's/^X//' >src/ansi/serverd.h <<'*-*-END-of-src/ansi/serverd.h-*-*'
  3687. X/*
  3688. X  AGREEMENT: This software can be used and distributed freely only as a
  3689. X  whole and not in parts, as long as you do not remove or alter the author
  3690. X  and copyright notices in the file defs.h; this notices are #define'd in
  3691. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3692. X  provided for your personal use, you may not alter the functions
  3693. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3694. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3695. X  any changes you may have made. No part of the source code bearing a
  3696. X  copyright notice can be included in commercial software systems without
  3697. X  written permission by the author.
  3698. X  By using this software you are bound by this agreement.
  3699. X  This software comes with no warranties and cannot be sold for profit.
  3700. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3701. X  files when distributing this software.
  3702. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3703. X  Use, duplication or disclosure by the Federal Government is subject to the
  3704. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3705. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3706. X*/
  3707. X
  3708. X#define LOAD_FILE         PATH "/.load"
  3709. X#define UNWANTED_HOSTSF      PATH "/unwanted.hosts"
  3710. X#define PRIVILEGED_HOSTSF PATH "/priv.hosts"
  3711. X#define WELCOMEF      PATH "/welcome.live"
  3712. *-*-END-of-src/ansi/serverd.h-*-*
  3713. echo x - src/ansi/start.h
  3714. sed 's/^X//' >src/ansi/start.h <<'*-*-END-of-src/ansi/start.h-*-*'
  3715. X/*
  3716. X  AGREEMENT: This software can be used and distributed freely only as a
  3717. X  whole and not in parts, as long as you do not remove or alter the author
  3718. X  and copyright notices in the file defs.h; this notices are #define'd in
  3719. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3720. X  provided for your personal use, you may not alter the functions
  3721. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3722. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3723. X  any changes you may have made. No part of the source code bearing a
  3724. X  copyright notice can be included in commercial software systems without
  3725. X  written permission by the author.
  3726. X  By using this software you are bound by this agreement.
  3727. X  This software comes with no warranties and cannot be sold for profit.
  3728. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3729. X  files when distributing this software.
  3730. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3731. X  Use, duplication or disclosure by the Federal Government is subject to the
  3732. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3733. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3734. X*/
  3735. X
  3736. X#define REPORT_SERVER_ACC   PATH "/.rep.server.ac"
  3737. X#define REPORT_SERVERD_ACC  PATH "/.rep.serverd.a"
  3738. X#define REPORT_START_ACC    PATH "/.rep.start.acc"
  3739. X#define REPORT_PQUEUE_ACC   PATH "/.rep.pqueue.ac"
  3740. X#define REPORT_START        PATH "/.report.start"
  3741. X#define CATMAIL            PATH "/catmail"
  3742. X#define SETUP_DIR sprintf (dir, "%s/lists/%s", PATH, sys.lists[i].alias)
  3743. X#define SERVER_PIDS        PID_SERVER ".*"
  3744. X#define TMP_LIVE_FILES        TMP_LIVE ".*"
  3745. X#define REPLY_FILES        ULISTPROCESSOR_REPLY "*"
  3746. *-*-END-of-src/ansi/start.h-*-*
  3747. echo x - src/ansi/sysmail.h
  3748. sed 's/^X//' >src/ansi/sysmail.h <<'*-*-END-of-src/ansi/sysmail.h-*-*'
  3749. X/*
  3750. X  AGREEMENT: This software can be used and distributed freely only as a
  3751. X  whole and not in parts, as long as you do not remove or alter the author
  3752. X  and copyright notices in the file defs.h; this notices are #define'd in
  3753. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3754. X  provided for your personal use, you may not alter the functions
  3755. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3756. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3757. X  any changes you may have made. No part of the source code bearing a
  3758. X  copyright notice can be included in commercial software systems without
  3759. X  written permission by the author.
  3760. X  By using this software you are bound by this agreement.
  3761. X  This software comes with no warranties and cannot be sold for profit.
  3762. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3763. X  files when distributing this software.
  3764. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3765. X  Use, duplication or disclosure by the Federal Government is subject to the
  3766. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3767. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3768. X*/
  3769. X
  3770. X#define SENT              PATH "/sent"
  3771. X#define RECEIVED_         PATH "/received"
  3772. X#define IDF               PATH "/.queue.id"
  3773. X#define QUEUE_DIR         PATH "/mqueue"
  3774. *-*-END-of-src/ansi/sysmail.h-*-*
  3775. echo x - src/nonansi/catmail.h
  3776. sed 's/^X//' >src/nonansi/catmail.h <<'*-*-END-of-src/nonansi/catmail.h-*-*'
  3777. X#define LOST_REQUESTS        PATH/lost+found"
  3778. X#define TAG_IDF            PATH/.tag.id"
  3779. X#define CATMAIL_TMP             PATH/.catmail.tmp"
  3780. *-*-END-of-src/nonansi/catmail.h-*-*
  3781. echo x - src/nonansi/defs.h
  3782. sed 's/^X//' >src/nonansi/defs.h <<'*-*-END-of-src/nonansi/defs.h-*-*'
  3783. X/*
  3784. X  AGREEMENT: This software can be used and distributed freely only as a
  3785. X  whole and not in parts, as long as you do not remove or alter the author
  3786. X  and copyright notices in the file defs.h; this notices are #define'd in
  3787. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3788. X  provided for your personal use, you may not alter the functions
  3789. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3790. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3791. X  any changes you may have made. No part of the source code bearing a
  3792. X  copyright notice can be included in commercial software systems without
  3793. X  written permission by the author.
  3794. X  By using this software you are bound by this agreement.
  3795. X  This software comes with no warranties and cannot be sold for profit.
  3796. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3797. X  files when distributing this software.
  3798. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3799. X  Use, duplication or disclosure by the Federal Government is subject to the
  3800. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3801. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3802. X*/
  3803. X
  3804. X#define PATH              "/usr/server
  3805. X#define WARNING           PATH/.warning"
  3806. X#define REPORT_SERVER     PATH/.report.server"
  3807. X#define REPORT_SERVERD    PATH/.report.daemon"
  3808. X#define REPORT_PQUEUE     PATH/.report.pqueue"
  3809. X#define REPORT_CATMAIL      PATH/.report.catmai"
  3810. X#define CONFIG            PATH/config"
  3811. X#define LIST              PATH/list -1 -L "
  3812. X#define SERVER            PATH/listproc -1 "
  3813. X#define SERVER_MAIL_FILE  PATH/requests"
  3814. X#define BATCH_FILE      PATH/batch"
  3815. X#define SERVERD           PATH/serverd"
  3816. X#define PQUEUE            PATH/pqueue"
  3817. X#define START             PATH/start"
  3818. X#define OWNERSF           PATH/owners"
  3819. X#define ALIASESF      PATH/.aliases"
  3820. X#define SERVERD_LOCK_FILE PATH/.lock.serverd"
  3821. X#define PQUEUE_LOCK_FILE  PATH/.lock.pqueue"
  3822. X#define PID_PQUEUE        PATH/.pid.pqueue"
  3823. X#define PID_SERVERD       PATH/.pid.daemon"
  3824. X#define PID_SERVER        PATH/.pid.server"
  3825. X#define PID_LIST          PATH/.pid.list"
  3826. X#define PID_QUEUED      PATH/.pid.queued"
  3827. X#define MAILFORWARD       PATH/.mailforward"
  3828. X#define ULISTPROCESSOR_REPLY      PATH/.reply"
  3829. X#define ARCHIVE_DIR      PATH/archives"
  3830. X#define OLD_SUBSCRIBERS   PATH/.oldsubscriber"
  3831. X#define OLD_ALIASES      PATH/.oldaliases"
  3832. X#define NEW_SUBSCRIBERS   PATH/.newsubscriber"
  3833. X#define NEW_ALIASES      PATH/.newaliases"
  3834. X#define    TMP_LIVE      PATH/.live"
  3835. *-*-END-of-src/nonansi/defs.h-*-*
  3836. echo x - src/nonansi/listproc.h
  3837. sed 's/^X//' >src/nonansi/listproc.h <<'*-*-END-of-src/nonansi/listproc.h-*-*'
  3838. X/*
  3839. X  AGREEMENT: This software can be used and distributed freely only as a
  3840. X  whole and not in parts, as long as you do not remove or alter the author
  3841. X  and copyright notices in the file defs.h; this notices are #define'd in
  3842. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3843. X  provided for your personal use, you may not alter the functions
  3844. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3845. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3846. X  any changes you may have made. No part of the source code bearing a
  3847. X  copyright notice can be included in commercial software systems without
  3848. X  written permission by the author.
  3849. X  By using this software you are bound by this agreement.
  3850. X  This software comes with no warranties and cannot be sold for:w profit.
  3851. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3852. X  files when distributing this software.
  3853. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3854. X  Use, duplication or disclosure by the Federal Government is subject to the
  3855. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3856. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3857. X*/
  3858. X
  3859. X#define MAIL_COPY         PATH/.messages"
  3860. X#define MSG_NO            PATH/.msgno"
  3861. X#define AWK_PROG          PATH/.awk"
  3862. X#define STATS_PROG        PATH/.stats"
  3863. X#define SERVER_MBOX       PATH/mbox"
  3864. X#define HELP_TOPICS       PATH/help/TOPICS"
  3865. X#define STDOUT          PATH/stdout"
  3866. X#define STDERR          PATH/stderr"
  3867. X#define SETUP_MESSAGE_IDSF sprintf (message_idsf, "%s/%s", PATH", MESSAGE_IDS_F)
  3868. X#define EXEC_STATS \
  3869. X  syscom ("%s %s %s %s %s %s", STATS_PROG, PATH", subscribersf,\
  3870. X          headersf, mailforwardf, params)
  3871. X
  3872. X#define REARRANGE_SUBSCRIBERS \
  3873. X  syscom ("%s/rev < %s | awk '{print $NF \"\\t\" $0}' | sort | \
  3874. Xsed 's/^.*\t//' | %s/rev > %s/sub.%s", PATH", subscribersf,\
  3875. X      PATH", PATH", sys.lists[listid].alias);\
  3876. X  mv (tsprintf ("%s/sub.%s", PATH", sys.lists[listid].alias), subscribersf)
  3877. X
  3878. X#define CAT_FILE \
  3879. X  syscom ("%s %s | %s/fwin -n -o %ld -b %ld | sed -e 's/^From />From /' | \
  3880. Xsed -e 's/^\\.$/\\\\./' >> %s", \
  3881. X      (compressed_source ? "zcat" : "cat"), fullname, PATH", offset,\
  3882. X          nbytes, mailforwardf)
  3883. *-*-END-of-src/nonansi/listproc.h-*-*
  3884. echo x - src/nonansi/misc.h
  3885. sed 's/^X//' >src/nonansi/misc.h <<'*-*-END-of-src/nonansi/misc.h-*-*'
  3886. X/*
  3887. X  AGREEMENT: This software can be used and distributed freely only as a
  3888. X  whole and not in parts, as long as you do not remove or alter the author
  3889. X  and copyright notices in the file defs.h; this notices are #define'd in
  3890. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3891. X  provided for your personal use, you may not alter the functions
  3892. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3893. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3894. X  any changes you may have made. No part of the source code bearing a
  3895. X  copyright notice can be included in commercial software systems without
  3896. X  written permission by the author.
  3897. X  By using this software you are bound by this agreement.
  3898. X  This software comes with no warranties and cannot be sold for profit.
  3899. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3900. X  files when distributing this software.
  3901. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3902. X  Use, duplication or disclosure by the Federal Government is subject to the
  3903. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3904. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3905. X*/
  3906. X
  3907. X#define SETUP_STRING sprintf (s, "%s/lists/%s/%s", PATH", alias, filename)
  3908. X#define SETUP_IGNOREDF sprintf (server_ignoredf, "%s/%s", PATH", IGNORED)
  3909. *-*-END-of-src/nonansi/misc.h-*-*
  3910. echo x - src/nonansi/serverd.h
  3911. sed 's/^X//' >src/nonansi/serverd.h <<'*-*-END-of-src/nonansi/serverd.h-*-*'
  3912. X/*
  3913. X  AGREEMENT: This software can be used and distributed freely only as a
  3914. X  whole and not in parts, as long as you do not remove or alter the author
  3915. X  and copyright notices in the file defs.h; this notices are #define'd in
  3916. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3917. X  provided for your personal use, you may not alter the functions
  3918. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3919. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3920. X  any changes you may have made. No part of the source code bearing a
  3921. X  copyright notice can be included in commercial software systems without
  3922. X  written permission by the author.
  3923. X  By using this software you are bound by this agreement.
  3924. X  This software comes with no warranties and cannot be sold for profit.
  3925. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3926. X  files when distributing this software.
  3927. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3928. X  Use, duplication or disclosure by the Federal Government is subject to the
  3929. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3930. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3931. X*/
  3932. X
  3933. X#define LOAD_FILE         PATH/.load"
  3934. X#define UNWANTED_HOSTSF      PATH/unwanted.hosts"
  3935. X#define PRIVILEGED_HOSTSF PATH/priv.hosts"
  3936. X#define WELCOMEF      PATH/welcome.live"
  3937. *-*-END-of-src/nonansi/serverd.h-*-*
  3938. echo x - src/nonansi/start.h
  3939. sed 's/^X//' >src/nonansi/start.h <<'*-*-END-of-src/nonansi/start.h-*-*'
  3940. X/*
  3941. X  AGREEMENT: This software can be used and distributed freely only as a
  3942. X  whole and not in parts, as long as you do not remove or alter the author
  3943. X  and copyright notices in the file defs.h; this notices are #define'd in
  3944. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3945. X  provided for your personal use, you may not alter the functions
  3946. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3947. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3948. X  any changes you may have made. No part of the source code bearing a
  3949. X  copyright notice can be included in commercial software systems without
  3950. X  written permission by the author.
  3951. X  By using this software you are bound by this agreement.
  3952. X  This software comes with no warranties and cannot be sold for profit.
  3953. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3954. X  files when distributing this software.
  3955. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3956. X  Use, duplication or disclosure by the Federal Government is subject to the
  3957. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3958. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3959. X*/
  3960. X
  3961. X#define REPORT_SERVER_ACC   PATH/.rep.server.ac"
  3962. X#define REPORT_SERVERD_ACC  PATH/.rep.serverd.a"
  3963. X#define REPORT_START_ACC    PATH/.rep.start.acc"
  3964. X#define REPORT_PQUEUE_ACC   PATH/.rep.pqueue.ac"
  3965. X#define REPORT_START        PATH/.report.start"
  3966. X#define CATMAIL            PATH/catmail"
  3967. X#define SETUP_DIR sprintf (dir, "%s/lists/%s", PATH", sys.lists[i].alias)
  3968. X#define SERVER_PIDS        PATH/.pid.server.*"
  3969. X#define TMP_LIVE_FILES        PATH/.live.*"
  3970. X#define REPLY_FILES        PATH/.reply*"
  3971. *-*-END-of-src/nonansi/start.h-*-*
  3972. echo x - src/nonansi/sysmail.h
  3973. sed 's/^X//' >src/nonansi/sysmail.h <<'*-*-END-of-src/nonansi/sysmail.h-*-*'
  3974. X/*
  3975. X  AGREEMENT: This software can be used and distributed freely only as a
  3976. X  whole and not in parts, as long as you do not remove or alter the author
  3977. X  and copyright notices in the file defs.h; this notices are #define'd in
  3978. X  the symbols VERSION and COPYRIGHT. Although you may alter the code
  3979. X  provided for your personal use, you may not alter the functions
  3980. X  create_header(), create_multi_recipient_header() and main() in list.c,
  3981. X  listproc.c and serverd.c (where applicable), and you may not redistribute
  3982. X  any changes you may have made. No part of the source code bearing a
  3983. X  copyright notice can be included in commercial software systems without
  3984. X  written permission by the author.
  3985. X  By using this software you are bound by this agreement.
  3986. X  This software comes with no warranties and cannot be sold for profit.
  3987. X  The AGREEMENT and COPYRIGHT notices should be included in all source
  3988. X  files when distributing this software.
  3989. X  COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas
  3990. X  Use, duplication or disclosure by the Federal Government is subject to the
  3991. X  restrictions set forth in FAR 52.227-19(c), Commercial Computer Software or,
  3992. X  for Department of Defense Users, by DFAR 252.227-7013(c)(1)(ii).
  3993. X*/
  3994. X
  3995. X#define SENT              PATH/sent"
  3996. X#define RECEIVED_         PATH/received"
  3997. X#define IDF               PATH/.queue.id"
  3998. X#define QUEUE_DIR         PATH/mqueue"
  3999. *-*-END-of-src/nonansi/sysmail.h-*-*
  4000. echo x - src/catmail.c
  4001. sed 's/^X//' >src/catmail.c <<'*-*-END-of-src/catmail.c-*-*'
  4002. X/*
  4003. X  ----------------------------------------------------------------------------
  4004. X  |                CATMAIL UTILITY                     |
  4005. X  |                                         |
  4006. X  |                  version 2.5                     |
  4007. X  |                                         |
  4008. X  | User contributed application.                         |
  4009. X  | Original author (1.0): Aad Nienhuis <Aad_Nienhuis@sconar.sco.uva.nl>     |
  4010. X  | Modified by (1.1): Tasos Kotsikonas                         |
  4011. X  | Enhanced by (2.0): Tasos Kotsikonas, Warren Burstein             |
  4012. X  | Enhanced by (2.1, 2.5): Tasos Kotsikonas                     |
  4013. X  ----------------------------------------------------------------------------
  4014. X
  4015. X  This is a utility that appends a mail message supplied by sendmail in 
  4016. X  stdin to the appropriate file, depending on the command line options
  4017. X  supplied. The application has to be setuid. If the incoming message
  4018. X  is for a moderated list and not from the moderator, append a NOTIFY request
  4019. X  to the requests file so that listproc will later notify the list owner,
  4020. X  soliciting his approval for posting the message.
  4021. X
  4022. X  The utility is to be used primarily in the host's aliases file when 
  4023. X  setting up aliases for various lists. To append to the system's requests
  4024. X  file it may be used as follows:
  4025. X
  4026. X    listproc: "|HOMEDIR/catmail -r -f"
  4027. X
  4028. X  To append to a list's mail file:
  4029. X
  4030. X    list_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f"
  4031. X
  4032. X  To append to a list's moderated file:
  4033. X
  4034. X    list_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f -m"
  4035. X
  4036. X  COMMAND LINE OPTIONS:
  4037. X    -L: The input is appened to the specified list's "mail" file.
  4038. X    -l: Same as -L.
  4039. X    -m: The input is appened to the specified list's "moderated" file.
  4040. X    and a copy is appended to the requests file to be forwarded
  4041. X    by listproc to the owner for approval.
  4042. X    -r: The input is appened to HOMEDIR/requests.
  4043. X    -f: The input is reformatted while appended.
  4044. X*/
  4045. X
  4046. X#include <stdio.h>
  4047. X#ifdef SYSLOG
  4048. X# ifdef ultrix
  4049. X#  include <sys/syslog.h>
  4050. X# else
  4051. X#  include <syslog.h>
  4052. X# endif
  4053. X#endif
  4054. X#include <string.h>
  4055. X#ifndef unknown_port
  4056. X# ifndef __NeXT__
  4057. X#  include <unistd.h>
  4058. X# else
  4059. X#  include <libc.h>
  4060. X# endif
  4061. X#endif
  4062. X#include <signal.h>
  4063. X#include <sys/types.h>
  4064. X#include <sys/stat.h>
  4065. X#include <pwd.h>
  4066. X#include <fcntl.h>
  4067. X#include <errno.h>
  4068. X#ifdef unknown_port
  4069. Xextern int errno;
  4070. X#endif
  4071. X#include <time.h>
  4072. X#include "defs.h"
  4073. X#include "catmail.h"
  4074. X#include "struct.h"
  4075. X#include "global.h"
  4076. X#if defined (__NeXT__) || defined (unknown_port)
  4077. X# include "next.h"
  4078. X#endif
  4079. X
  4080. X#ifdef __STDC__
  4081. X# include <stdarg.h>
  4082. Xextern char *tsprintf (char *, ...);
  4083. X#else
  4084. X# include <varargs.h>
  4085. Xextern char *tsprintf ();
  4086. X#endif
  4087. Xextern int  sys_config (FILE *, SYS *);
  4088. Xextern void setup_string (char *, char *, char *);
  4089. Xextern int  _getopt (int, char **, char *);
  4090. Xextern char *upcase (char *);
  4091. Xextern int  get_list_id (char *, SYS *, int);
  4092. Xextern void report_progress (FILE *, char *, int);
  4093. Xextern int  lock_file (char *, int, int, BOOLEAN);
  4094. Xextern void unlock_file (int);
  4095. Xextern BOOLEAN extract_sender (char *);
  4096. Xextern BOOLEAN owner_listed (char *, char *, char *, FILE *);
  4097. Xextern int  otoi (char *);
  4098. Xextern int cat_append (char *, char *);
  4099. Xextern int echo (char *, char *);
  4100. Xextern BOOLEAN strinstr (char *, char *);
  4101. X
  4102. Xvoid   main (int, char **, char **);
  4103. Xvoid   catmail (FILE *, FILE *, FILE *, FILE *, int);
  4104. Xint    get_tag_id (void);
  4105. Xvoid   usage (void);
  4106. Xint    gexit (int);
  4107. X
  4108. Xvoid main (int argc, char **argv, char **envp)
  4109. X{
  4110. X  char *options = "rfml:L:", *getenv();
  4111. X  extern char *optarg;
  4112. X  extern int optopt;
  4113. X#ifdef ultrix
  4114. X  time_t t;
  4115. X#else
  4116. X  long int t;
  4117. X#endif
  4118. X  int c, nlists, tag = 0;
  4119. X  char *list_alias = NULL, *mask;
  4120. X  char file [MAX_LINE];
  4121. X  char header [MAX_LINE];
  4122. X  char msg [MAX_LINE];
  4123. X  FILE *mail, *mailf = NULL, *pipe = NULL;
  4124. X  struct passwd *pwentry;
  4125. X
  4126. X  while ((c = _getopt (argc, argv, options)) != EOF)
  4127. X    switch ((char) c) {
  4128. X      case 'm': moderated = TRUE; break;
  4129. X      case 'f': reformat = TRUE; break;
  4130. X      case 'r': requests = TRUE; moderated = FALSE; break;
  4131. X      case 'l':
  4132. X      case 'L': list_alias = upcase (optarg); break;
  4133. X      case ':':
  4134. X    fprintf (stderr, "catmail: Option '%c' requires an argument.\n",
  4135. X         optopt);
  4136. X    exit (3);
  4137. X      case '?':
  4138. X      default:
  4139. X        usage();
  4140. X    }
  4141. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  4142. X    umask (otoi (mask));
  4143. X  else
  4144. X    mask = "066",
  4145. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  4146. X
  4147. X  signal (SIGALRM, (void (*)()) gexit);
  4148. X  alarm (120);    /* Timeout after 2 mins */
  4149. X#ifdef SYSLOG
  4150. X  openlog ("ListProcessor: catmail", LOG_NDELAY
  4151. X# ifndef i386
  4152. X       |LOG_NOWAIT
  4153. X# endif
  4154. X       , SYSLOG);
  4155. X# ifndef ultrix
  4156. X  setlogmask (LOG_UPTO (LOG_INFO));
  4157. X# endif
  4158. X#else
  4159. X  if ((report = fopen (REPORT_CATMAIL, "a+")) == NULL)
  4160. X    fprintf (stderr, "catmail: Could not open %s\n", REPORT_CATMAIL),
  4161. X    exit (1);
  4162. X  chmod (REPORT_CATMAIL, 384);
  4163. X#endif
  4164. X
  4165. X  if ((pwentry = getpwuid (getuid ())) == NULL)
  4166. X    report_progress (report, "main(): Invalid user account", TRUE),
  4167. X    exit (3);
  4168. X  if (requests)        /* Select file to append to */
  4169. X    tty_echo = FALSE,
  4170. X    report_progress (report, "\n--- NEW MAIL FOR LISTPROCESSOR ---\n", FALSE),
  4171. X    report_progress (report, tsprintf ("Access granted to user id %d (%s)",
  4172. X                       getuid(), pwentry->pw_name), TRUE),
  4173. X    strcpy (file, SERVER_MAIL_FILE);
  4174. X  else {
  4175. X    if (list_alias == NULL)
  4176. X      report_progress (report, "\ncatmail: No list to process", TRUE),
  4177. X      exit (3);
  4178. X    nlists = sys_config (report, &sys);
  4179. X    if ((listid = get_list_id (list_alias, &sys, nlists)) < 0)
  4180. X      report_progress (report, tsprintf ("\ncatmail: Unknown list %s",
  4181. X                     list_alias), TRUE),
  4182. X      exit (3);
  4183. X    setup_string (file, list_alias,
  4184. X     (moderated ? LIST_MODERATED_F : LIST_MAIL_FILE));
  4185. X    tty_echo = FALSE;
  4186. X    report_progress (report, tsprintf ("\n--- NEW MAIL FOR %s ---\n",
  4187. X                       list_alias), FALSE);
  4188. X    report_progress (report, tsprintf ("Access granted to user id %d (%s)",
  4189. X                       getuid(), pwentry->pw_name), TRUE);
  4190. X    setup_string (list_mail_f, list_alias, LIST_MAIL_FILE);
  4191. X  }
  4192. X#ifndef NO_LOCKS
  4193. X  signal (SIGINT, (void (*)()) gexit);
  4194. X  if ((lfd = lock_file (file, O_RDWR | O_CREAT, 0640, TRUE)) < 0)
  4195. X    switch (lfd) {
  4196. X    case CANT_OPEN:
  4197. X      report_progress (report, tsprintf ("\nCould not stat file %s", file),
  4198. X               TRUE);
  4199. X      exit (1);
  4200. X    case CANT_LOCK:
  4201. X      if (requests)
  4202. X    strcpy (file, LOST_REQUESTS);
  4203. X      else
  4204. X        setup_string (file, list_alias, LOST_MAIL);
  4205. X      report_progress (report, tsprintf ("\nCANNOT LOCK FILE: SAVING UNDER %s",
  4206. X                     file), TRUE);
  4207. X    }
  4208. X  if (moderated) { /* Also lock SERVER_MAIL_FILE and LIST_MAIL_FILE */
  4209. X    if ((lfd2 = lock_file (SERVER_MAIL_FILE, O_RDWR | O_CREAT, 0640, TRUE)) < 0)
  4210. X      switch (lfd2) {
  4211. X      case CANT_OPEN:
  4212. X        report_progress (report, tsprintf ("\nCould not stat file %s",
  4213. X                       SERVER_MAIL_FILE), TRUE);
  4214. X        gexit (1);
  4215. X      case CANT_LOCK:
  4216. X        report_progress (report,
  4217. X             tsprintf ("\nCANNOT LOCK FILE %s: TAKING MY CHANCES",
  4218. X                   SERVER_MAIL_FILE), TRUE);
  4219. X      }
  4220. X    if ((lfd3 = lock_file (list_mail_f, O_RDWR | O_CREAT, 0640, TRUE)) < 0)
  4221. X      switch (lfd3) {
  4222. X      case CANT_OPEN:
  4223. X        report_progress (report, tsprintf ("\nCould not stat file %s",
  4224. X                       list_mail_f), TRUE);
  4225. X        gexit (1);
  4226. X      case CANT_LOCK:
  4227. X        report_progress (report,
  4228. X             tsprintf ("\nCANNOT LOCK FILE %s: TAKING MY CHANCES",
  4229. X                   list_mail_f), TRUE);
  4230. X      }
  4231. X  }
  4232. X#endif
  4233. X  OPEN_FILE (mail, file, "a+", "main");
  4234. X  sprintf (header, "/tmp/.%d.1.catmail", getpid());
  4235. X  sprintf (msg, "/tmp/.%d.2.catmail", getpid());
  4236. X  if (moderated) {
  4237. X    tag = get_tag_id();
  4238. X    OPEN_FILE (pipe, header, "w", "main");
  4239. X    t = time (0);
  4240. X    fprintf (pipe, "From %s %s\nNOTIFY\n\
  4241. XApproval request from %s for posting \
  4242. Xthe following\nmessage to moderated list %s. If approved, send the following \
  4243. Xrequest to\n%s:\n\nAPPROVE %s <password> %d\n\n\
  4244. XIf the message is to be discarded, reply with the following request:\n\n\
  4245. XDISCARD %s <password> %d\n\n\
  4246. X----------------------------- message follows ------------------------------\n",
  4247. X         sys.lists[listid].owner, ctime (&t), sys.server.address,
  4248. X         list_alias, sys.server.address, list_alias, tag, list_alias, tag);
  4249. X    fclose (pipe);
  4250. X    OPEN_FILE (pipe, msg, "w", "main");
  4251. X    OPEN_FILE (mailf, list_mail_f, "a+", "main");
  4252. X  }
  4253. X  catmail (stdin, mail, mailf, pipe, tag);
  4254. X  fclose (mail);
  4255. X  if (pipe)
  4256. X    fclose (pipe);
  4257. X  if (mailf)
  4258. X    fclose (mailf);
  4259. X#ifdef SYSLOG
  4260. X  closelog ();
  4261. X#else
  4262. X  fclose (report);
  4263. X#endif
  4264. X  if (moderated) /* Message was not from moderator */
  4265. X    cat_append (header, SERVER_MAIL_FILE),
  4266. X    cat_append (msg, SERVER_MAIL_FILE);
  4267. X  unlink (header);
  4268. X  unlink (msg);
  4269. X  gexit (0);
  4270. X}
  4271. X
  4272. X/*
  4273. X  Append the input file to the output file, possibly pipe it also to another
  4274. X  output file, and possibly reformat it.
  4275. X  Turn moderation flag off if the message is from one of the list owners.
  4276. X*/
  4277. X
  4278. Xvoid catmail (FILE *in, FILE *out, FILE *mailf, FILE *copy, int tag)
  4279. X{
  4280. X  char buf [MAX_LINE];
  4281. X  char sender [MAX_LINE];
  4282. X
  4283. X  sender[0] = RESET (buf);
  4284. X  fgets (buf, MAX_LINE - 2, in);  /* Do not format very first "From " line */
  4285. X  if (feof (in)) {
  4286. X    moderated = FALSE;
  4287. X    return;
  4288. X  }
  4289. X  strcpy (sender, buf);
  4290. X
  4291. X  extract_sender (sender); /* Get sender; ignore address syntax correctness */
  4292. X  upcase (sender);
  4293. X  if (moderated &&
  4294. X      (owner_listed (OWNERSF, sender, sys.lists[listid].alias, report) ||
  4295. X       strinstr (MAILER_DAEMON, sender)))
  4296. X    out = mailf, /* Output file is now 'mail' instead of 'moderated' */
  4297. X    moderated = FALSE; /* Message from moderator */
  4298. X  fputs (buf, out);
  4299. X  if (moderated && !strncmp (buf, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))
  4300. X    fprintf (out, "Message-Tag: %d\n", tag),
  4301. X    fprintf (copy, ">%sMessage-Tag: %d\n", buf, tag);
  4302. X  RESET (buf);
  4303. X  while (!feof (in)) {
  4304. X    fgets (buf, MAX_LINE - 2, in);
  4305. X    if (buf[0] != EOS) {
  4306. X      if (reformat &&
  4307. X      !strncmp (buf, START_OF_MESSAGE, strlen (START_OF_MESSAGE))) {
  4308. X        putc ('>', out);
  4309. X    if (copy)
  4310. X      putc ('>', copy);
  4311. X      }
  4312. X      fputs (buf, out);
  4313. X      if (copy)
  4314. X    fputs (buf, copy);
  4315. X    }
  4316. X    RESET (buf);
  4317. X  }
  4318. X}
  4319. X
  4320. X/*
  4321. X  Get unique tag id for moderated message.
  4322. X*/
  4323. X
  4324. Xint get_tag_id ()
  4325. X{
  4326. X  FILE *id;
  4327. X  int id_no = 1;
  4328. X
  4329. X  if ((id = fopen (TAG_IDF, "r")) != NULL)
  4330. X    fscanf (id, "%d\n", &id_no),
  4331. X    fclose (id);
  4332. X  echo (tsprintf ("%d", id_no + 1), TAG_IDF);
  4333. X  return id_no;
  4334. X}
  4335. X
  4336. Xvoid usage ()
  4337. X{
  4338. X  fprintf (stderr, "Usage: catmail {<<-L | -l> LIST_ALIAS [-m]> | <-r>} [-f]]\n\
  4339. X-L: Append to HOMEDIR/lists/LIST_ALIAS/mail.\n\
  4340. X-l: Same -L.\n\
  4341. X-m: Append to HOMEDIR/lists/LIST_ALIAS/moderated instead.\n\
  4342. X-r: Append to HOMEDIR/requests instead.\n\
  4343. X-f: Reformat messages before appending.\n\
  4344. X");
  4345. X  exit (3);
  4346. X}
  4347. X
  4348. X/*
  4349. X  Graceful exit.
  4350. X*/
  4351. X
  4352. Xint gexit (int exitcode)
  4353. X{
  4354. X#ifndef NO_LOCKS
  4355. X  unlock_file (lfd);
  4356. X  unlock_file (lfd2);
  4357. X  unlock_file (lfd3);
  4358. X#endif
  4359. X  exit (exitcode);
  4360. X}
  4361. *-*-END-of-src/catmail.c-*-*
  4362. echo x - src/farch.c
  4363. sed 's/^X//' >src/farch.c <<'*-*-END-of-src/farch.c-*-*'
  4364. X/*
  4365. X  ----------------------------------------------------------------------------
  4366. X  |                        FILE ARCHIVING UTILITY                 |
  4367. X  |                                                                          |
  4368. X  |                               Version 3.1                     |
  4369. X  |                                                                          |
  4370. X  |                (or, when Computer Science gets to you)                   |
  4371. X  |                                                                          |
  4372. X  |                    Written by Anastasios Kotsikonas                      |
  4373. X  |                           (tasos@cs.bu.edu)                              |
  4374. X  |                                                                          |
  4375. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  4376. X  | whole and not in parts, as long as you do not remove or alter the author |
  4377. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  4378. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  4379. X  | provided for your personal use, you may not alter the functions          |
  4380. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  4381. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  4382. X  | any changes you may have made. No part of the source code bearing a         |
  4383. X  | copyright notice can be included in commercial software systems without  |
  4384. X  | written permission by the author.                         |
  4385. X  | By using this software you are bound by this agreement.                  |
  4386. X  | This software comes with no warranties and cannot be sold for profit.    |
  4387. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  4388. X  | files when distributing this software.                                   |
  4389. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  4390. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  4391. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer         |
  4392. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  4393. X  | (ii).                                     |
  4394. X  ----------------------------------------------------------------------------
  4395. X
  4396. X  farch archives files into the specified directories, possibly splitting
  4397. X  them into smaller parts. It then updates the DIR file of the appropriate
  4398. X  archive. Split files have numbers appended to their original names;
  4399. X  non-split files have their names intact. Binary files are uuencoded before
  4400. X  processed, and all output files are compressed.
  4401. X
  4402. X  COMMAND LINE OPTIONS:
  4403. X    -n: Do not split input files.
  4404. X    -t: Tar all input files.
  4405. X    -b: Input files are binary; uuencode.
  4406. X    -B: Input files are binary; do not uuencode, do not split.
  4407. X    -s: Set the maximum size of each of the split subparts in kilobytes.
  4408. X    -d: Specify the actual directory that the archived files will reside.
  4409. X    -p: Specify the password for the private archive.
  4410. X    -D: Specify a descriptive string to be appended to each DIR file.
  4411. X    -r: Remove the specified files from the specified archive.
  4412. X    -a: Specify the archive where the input files will be archived.
  4413. X    -Z: Turn of file compression.
  4414. X    -u: Update existing file.
  4415. X
  4416. X  WARNING: The program can also archive directory files, if these can be
  4417. X  of any use.
  4418. X
  4419. X  Algorithm:
  4420. X  {
  4421. X    Process command line arguments; allocate buffer_size
  4422. X    Open master archive and all subarchives as necessary to get to the
  4423. X      specified (path-to-) archive; get path to specified archive
  4424. X    Verify existsence of target directory -- create it if necessary
  4425. X    Tar files, if so requested
  4426. X    for (each input file) {
  4427. X      open
  4428. X      get filesize
  4429. X      if (-r)
  4430. X        remove file
  4431. X      else {
  4432. X        if (-b)
  4433. X      uuencode file
  4434. X        if (-n or filesize <= buffer_size) { -- Do not split --
  4435. X      if (-b)
  4436. X        copy uuencoded file into target directory
  4437. X      if (file does not exist in target directory)
  4438. X        copy it to target directory
  4439. X        compress it
  4440. X      update (archive's directory)
  4441. X        }
  4442. X        else split file {
  4443. X      while (not eof) {
  4444. X        get unique output filename
  4445. X        fwrite (leftover bytes from previous chunk)
  4446. X        fread (new chunk)
  4447. X        if (! -b) {
  4448. X          locate nearest newline from the end of the buffer
  4449. X          copy those skipped bytes to leftover
  4450. X        }
  4451. X        fwrite (new modified chunk)
  4452. X        compress it
  4453. X      }
  4454. X      fwrite (any leftovers)
  4455. X      compress part
  4456. X      update (archive's directory)
  4457. X        }
  4458. X      }
  4459. X    }
  4460. X  }
  4461. X*/
  4462. X
  4463. X#include <stdio.h>
  4464. X#include <sys/types.h>
  4465. X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
  4466. X && !defined (sequent) && !defined (unknown_port)
  4467. X# include <malloc.h>
  4468. X#endif
  4469. X#ifndef unknown_port
  4470. X# ifndef __NeXT__
  4471. X#  include <unistd.h>
  4472. X# else
  4473. X#  include <libc.h>
  4474. X# endif
  4475. X#endif
  4476. X#include <sys/stat.h>
  4477. X#include <string.h>
  4478. X#include <errno.h>
  4479. X#ifdef unknown_port
  4480. Xextern int errno;
  4481. X#endif
  4482. X#include <signal.h>
  4483. X#include "defs.h"
  4484. X#include "struct.h"
  4485. X#include "global.h"
  4486. X#include "listproc.h"
  4487. X
  4488. X#define DEFAULT_SIZE    64 * 1024
  4489. X
  4490. X#ifdef __STDC__
  4491. X# include <stdarg.h>
  4492. Xextern int  syscom (char *, ...);
  4493. X#else
  4494. X# include <varargs.h>
  4495. Xextern int  syscom ();
  4496. X#endif
  4497. Xextern char *extract_filename (char *);
  4498. Xextern char *locase (char *);
  4499. X#ifndef __NeXT__
  4500. Xextern long int atol (char *);
  4501. X#else
  4502. Xextern long int atol (const char *);
  4503. X#endif
  4504. Xextern int  _getopt (int, char **, char *);
  4505. Xextern BOOLEAN make_indexes (char *, char *, char *, char *, char *);
  4506. Xextern BOOLEAN mkdir1 (char *, char *, char *);
  4507. Xextern char *mystrdup (char *);
  4508. Xextern int  otoi (char *);
  4509. X
  4510. Xvoid   main (int , char **);
  4511. Xvoid   uuencode (FILE **, char *, char *, struct stat *, BOOLEAN);
  4512. Xint    update (char *, char *, long int, long int *, char *, char *,
  4513. X           struct stat, BOOLEAN, BOOLEAN, BOOLEAN);
  4514. Xvoid   remove_files (char *, char *, long int, struct stat, BOOLEAN);
  4515. Xvoid   usage (void);
  4516. Xvoid   do_archive (int, int, char **, char *, char *, char *, char *, char *,
  4517. X           long int, BOOLEAN, BOOLEAN, BOOLEAN, BOOLEAN, BOOLEAN,
  4518. X           BOOLEAN);
  4519. Xint    get_archive (char **, char *, char *, BOOLEAN);
  4520. Xint    get_dir (char *, char **, char *);
  4521. Xint    tar_files (int, int, char **, char *);
  4522. Xvoid   rmfiles (int, int, char **, char *, BOOLEAN, BOOLEAN);
  4523. Xint    gexit (int);
  4524. X
  4525. Xchar *uue_file, *archives_mask, *comment;
  4526. X
  4527. Xvoid main (int argc, char **argv)
  4528. X{
  4529. X  long int size = DEFAULT_SIZE;
  4530. X  char *buf, *arch = NULL, *newdir = NULL, *dir, fullpath[10240],
  4531. X       *tarf, *password = NULL, *options = "nbBs:a:d:t:p:D:urZU", *text = "";
  4532. X  int c;
  4533. X  BOOLEAN bin = FALSE, tar = FALSE, split = TRUE, uue = FALSE,
  4534. X    remove_files = FALSE, no_compression = FALSE, updatef = FALSE;
  4535. X  extern char *optarg, *getenv();
  4536. X  extern int optopt, optind;
  4537. X
  4538. X  buf = (char *) malloc (size * sizeof (char));
  4539. X  dir = (char *) malloc (sizeof (char));
  4540. X  while ((c = _getopt (argc, argv, options)) != EOF)
  4541. X    switch ((char) c) {
  4542. X    case 'n': split = FALSE; break;
  4543. X    case 't': tar = TRUE; tarf = optarg;
  4544. X    case 'b': bin = TRUE; uue = TRUE; break;
  4545. X    case 'B': bin = TRUE; uue = FALSE; split = FALSE; break;
  4546. X    case 's': size = (long) atol (optarg) * 1024;
  4547. X                if (size <= 0)
  4548. X                fprintf (stderr, "How am I supposed to allocate %ld bytes?\n",
  4549. X                         size),
  4550. X                exit (3);
  4551. X              free ((char *) buf);
  4552. X              if ((buf = (char *) malloc (size * sizeof (char))) == NULL)
  4553. X                fprintf (stderr, "Size too big; not enough memory.\n"),
  4554. X                exit (11);
  4555. X              break;
  4556. X    case 'a': arch = locase (optarg); break;
  4557. X    case 'd': newdir = optarg;
  4558. X              if (*newdir != '/')
  4559. X                fprintf (stderr, "Must specify full path for the directory.\n"),
  4560. X                exit (3);
  4561. X              break;
  4562. X    case 'p': password = locase (optarg); break;
  4563. X    case 'D': text = optarg; break;
  4564. X    case 'r': remove_files = TRUE; break;
  4565. X    case 'Z': no_compression = TRUE; break;
  4566. X    case 'u': updatef = TRUE; break;
  4567. X    case 'U': usage ();
  4568. X    case ':': fprintf (stderr, "Option '%c' requires an argument.\n", optopt);
  4569. X              exit (3);
  4570. X    case '?':
  4571. X    default:
  4572. X      fprintf (stderr, "Unrecognized option '%c'.\n", optopt);
  4573. X      usage ();
  4574. X    }
  4575. X
  4576. X  if (optind == argc) {
  4577. X    fprintf (stderr, "farch: filename(s) missing.\n");
  4578. X    goto abort;
  4579. X  }
  4580. X
  4581. X  if (!(archives_mask = getenv ("ULISTPROC_ARCHIVES_UMASK")))
  4582. X    archives_mask = "066";
  4583. X
  4584. X  if (get_archive (&arch, fullpath, password, remove_files) &&
  4585. X      (remove_files || get_dir (newdir, &dir, fullpath))) {
  4586. X    if (remove_files)
  4587. X      rmfiles (optind, argc, argv, fullpath, no_compression, 0);
  4588. X    else {
  4589. X      if (tar)
  4590. X    if (tar_files (optind, argc, argv, tarf))
  4591. X      argc = optind + 1;
  4592. X    else 
  4593. X      goto abort;
  4594. X      do_archive (optind, argc, argv, buf, fullpath, arch, dir, text, size, bin,
  4595. X          uue, split, tar, no_compression, updatef);
  4596. X      if (tar)
  4597. X    unlink (tarf);
  4598. X    }
  4599. X  }
  4600. X  abort:
  4601. X  free ((char *) dir);
  4602. X  free ((char *) buf);
  4603. X}
  4604. X
  4605. X/*
  4606. X  uuencode a file.
  4607. X*/
  4608. X
  4609. Xvoid uuencode (FILE **fin, char *file, char *infile, struct stat *finbuf,
  4610. X           BOOLEAN tar)
  4611. X{
  4612. X  fclose (*fin);
  4613. X  printf ("\t- uuencoding...\n");
  4614. X  syscom ("uuencode %s %s%s > %s", file, infile, (tar ? ".tar" : ""),
  4615. X      (uue_file = mystrdup (tmpnam (NULL))));
  4616. X  *fin = fopen (uue_file, "r");
  4617. X  stat (uue_file, finbuf);
  4618. X}
  4619. X
  4620. X/*
  4621. X  tar all input files into 'tarf'.
  4622. X*/
  4623. X
  4624. Xint tar_files (int optind, int argc, char **argv, char *tarf)
  4625. X{
  4626. X  FILE *fin, *fout;
  4627. X  char files[10000];
  4628. X  int original = optind;
  4629. X
  4630. X  if ((fout = fopen (tarf, "w")) == NULL) {
  4631. X    fprintf (stderr, "Cannot write to tar file %s\n", tarf);
  4632. X    return 0;
  4633. X  }
  4634. X  fclose (fout);
  4635. X  unlink (tarf);
  4636. X  printf ("tarring...\n");
  4637. X  RESET (files);
  4638. X  while (optind < argc) {
  4639. X    if ((fin = fopen (argv[optind], "r")) == NULL) {
  4640. X      fprintf (stderr, "Unable to open %s for reading.\n", argv[optind]);
  4641. X      return 0;
  4642. X    }
  4643. X    fclose (fin);
  4644. X    sprintf (files + strlen (files), "%s ", argv[optind++]);
  4645. X  }
  4646. X  syscom ("tar -cf %s %s", tarf, files);
  4647. X  argv[original] = tarf;
  4648. X  return 1;
  4649. X}
  4650. X
  4651. X/*
  4652. X  Remove the file from the archive, if found.
  4653. X*/
  4654. X
  4655. Xvoid rmfiles (int optind, int argc, char **argv, char *path,
  4656. X          BOOLEAN no_compression, BOOLEAN update_dirf_only)
  4657. X{
  4658. X  char dirf[10240];
  4659. X  char file[10240];
  4660. X  char fullpath[10240];
  4661. X  char _fullpath[10240];
  4662. X  char fullname[10240];
  4663. X  char desc[10240];
  4664. X  char *s, *tmpdir;
  4665. X  BOOLEAN continued, found, match;
  4666. X  int cnt, _cnt, i;
  4667. X  long int count;
  4668. X  FILE *fin, *fout;
  4669. X  struct stat sbuf;
  4670. X
  4671. X  while (optind < argc) { /* Process each file */
  4672. X
  4673. X    s = argv[optind] + strlen (argv[optind]) - 1;
  4674. X    while (s != argv[optind] && *s == '/')  /* Remove trailing / */
  4675. X      *(s--) = EOS;
  4676. X
  4677. X    i = strlen (argv[optind]);
  4678. X    if (i > 2 && argv[optind][i - 2] == '.' && argv[optind][i - 1] == 'Z')
  4679. X      argv[optind][i - 2] = EOS;
  4680. X
  4681. X    if (!update_dirf_only)
  4682. X      printf ("%s: ", argv[optind]),
  4683. X      fflush (stdout);
  4684. X    RESET (dirf);
  4685. X    sprintf (dirf, "%s/%s", path, DIRF);
  4686. X    if (stat (dirf, &sbuf)) {
  4687. X      printf ("not removed\n");
  4688. X      fprintf (stderr, "Cannot access index %s for reading.\n", dirf);
  4689. X      exit (1);
  4690. X    }
  4691. X    signal (SIGINT, SIG_IGN);
  4692. X    syscom ("mv %s %s", dirf, (tmpdir = mystrdup (tmpnam (NULL))));
  4693. X    if ((fout = fopen (dirf, "w")) == NULL) {
  4694. X      fprintf (stderr, "Unable to open %s for writing.\nSEVERE ERROR: The \
  4695. Xarchive is now in an inconsistent state with no DIR file.\nIts DIR file can be \
  4696. Xfound in /tmp. Move %s to %s\n", dirf, tmpdir, dirf);
  4697. X      free ((char *) tmpdir);
  4698. X      exit (1);
  4699. X    }
  4700. X    if ((fin = fopen (tmpdir, "r")) == NULL) { 
  4701. X      fprintf (stderr, "Unable to open %s for reading. Cannot proceed.\n",
  4702. X           tmpdir);
  4703. X      if (stat (dirf, &sbuf))
  4704. X    fputs ("SEVERE ERROR: The archive now has NO DIR file; DIR file \
  4705. Xlost!!!\n", stderr);
  4706. X      else
  4707. X    fputs ("Archive intact!\n", stderr);
  4708. X      free ((char *) tmpdir);
  4709. X      exit (1);
  4710. X    }
  4711. X    RESET (fullpath);
  4712. X    found = FALSE;
  4713. X    while (!feof (fin)) { /* Get location and file-count of file */
  4714. X      file[0] = RESET (_fullpath);
  4715. X      fscanf (fin, "%s %d ", file, &_cnt);
  4716. X      match = FALSE;
  4717. X      if (file[0] != EOS) {
  4718. X    locase (file);
  4719. X    if (!strcmp (argv[optind], file))
  4720. X      match = found = TRUE;
  4721. X    if (!match)
  4722. X      fprintf (fout, "%s %d ", file, _cnt);
  4723. X    for (i = 0; i < abs (_cnt); ++i) {
  4724. X      fscanf (fin, "%ld ", &count);
  4725. X      if (!match)
  4726. X        fprintf (fout, "%ld ", count);
  4727. X    }
  4728. X    fscanf (fin, "%s", _fullpath);
  4729. X    if (!match)
  4730. X      fprintf (fout, "%s", _fullpath);
  4731. X    else
  4732. X      cnt = _cnt,
  4733. X      strcpy (fullpath, _fullpath);
  4734. X    do { /* Get file description */
  4735. X      RESET (desc);
  4736. X      fgets (desc, MAX_LINE - 2, fin);
  4737. X      if (desc [0] != EOS && desc[strlen (desc) - 1] == '\n')
  4738. X        desc[strlen (desc) - 1] = EOS;
  4739. X      continued = FALSE;
  4740. X      if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
  4741. X        desc[strlen (desc) - 1] = EOS,
  4742. X        continued = TRUE;
  4743. X      if (!match) {
  4744. X        fprintf (fout, "%s", desc);
  4745. X        if (continued)
  4746. X          fprintf (fout, "\\");
  4747. X        fputs ("\n", fout);
  4748. X      }
  4749. X      else {
  4750. X        if (!comment)
  4751. X          comment = (char *) malloc (strlen (desc) + 3),
  4752. X          *comment = EOS;
  4753. X        else
  4754. X          comment = (char *) realloc ((char *) comment, strlen (comment) +
  4755. X                      strlen (desc) + 3);
  4756. X        strcat (comment, desc);
  4757. X        if (continued)
  4758. X          strcat (comment, "\\\n");
  4759. X      }
  4760. X    } while (continued);
  4761. X      }
  4762. X    }
  4763. X    if (!found)
  4764. X      printf ("not found in %s", dirf);
  4765. X    else if (!update_dirf_only) { /* Remove all parts */
  4766. X      printf ("removing parts: ");
  4767. X      fflush (stdout);
  4768. X      for (i = 1; i <= abs (cnt); i++) {
  4769. X    RESET (fullname);
  4770. X    if (abs (cnt) > 1)
  4771. X      sprintf (fullname, "%s/%s%d", fullpath, argv[optind], i);
  4772. X    else
  4773. X      sprintf (fullname, "%s/%s", fullpath, argv[optind]);
  4774. X    if (stat (fullname, &sbuf)) {
  4775. X      strcat (fullname, ".Z"); /* Check for compressed file */
  4776. X      if (no_compression || stat (fullname, &sbuf))
  4777. X        printf ("%d (not found) ", i),
  4778. X        fflush (stdout);
  4779. X      else {
  4780. X        printf ("%d ", i);
  4781. X        if (unlink (fullname))
  4782. X          printf ("(errno %d) ", errno);
  4783. X        fflush (stdout);
  4784. X      }
  4785. X    }
  4786. X    else {
  4787. X      printf ("%d ", i);
  4788. X      if (unlink (fullname))
  4789. X        printf ("(errno %d) ", errno);
  4790. X      fflush (stdout);
  4791. X    }
  4792. X      }
  4793. X    }
  4794. X      else
  4795. X    printf ("\t- updating...");
  4796. X    fclose (fin);
  4797. X    fclose (fout);
  4798. X    signal (SIGINT, SIG_DFL);
  4799. X    ++optind;
  4800. X    puts ("");
  4801. X    unlink (tmpdir);
  4802. X  }
  4803. X  free ((char *) tmpdir);
  4804. X}
  4805. X
  4806. X/*
  4807. X  Check for duplicate file name and return if so. Otherwise, update the
  4808. X  archive's directory.
  4809. X*/
  4810. X
  4811. Xint update (char *path, char *filename, long int count, long int *filesizes,
  4812. X        char *dir, char *text, struct stat finbuf, BOOLEAN pure_bin,
  4813. X        BOOLEAN no_compression, BOOLEAN updatef)
  4814. X{
  4815. X  char dirf[10240];
  4816. X  char file[10240];
  4817. X  char fullpath[10240];
  4818. X  char desc[10240];
  4819. X  char stripped_file[10240];
  4820. X  char reply[80];
  4821. X  BOOLEAN continued, found = FALSE;
  4822. X  int cnt, i;
  4823. X  FILE *fout;
  4824. X
  4825. X  strcpy (stripped_file, filename);
  4826. X  i = strlen (stripped_file);
  4827. X  if (i > 2 && stripped_file [i - 2] == '.' && stripped_file [i - 1] == 'Z')
  4828. X    stripped_file [i - 2] = EOS;
  4829. X  RESET (dirf);
  4830. X  sprintf (dirf, "%s/%s", path, DIRF);
  4831. X  if ((fout = fopen (dirf, "r")) == NULL) {
  4832. X    fprintf (stderr, "Unable to open index %s for reading.\nFile %s \
  4833. Xnot archived. Remove output file(s) from %s\n", dirf, filename, dir);
  4834. X    exit (1);
  4835. X  }
  4836. X  while (!feof (fout)) { /* Get location and file-count of file */
  4837. X    file[0] = RESET (fullpath);
  4838. X    fscanf (fout, "%s %d %s", file, &cnt, fullpath);
  4839. X    do { /* Get file description */
  4840. X      RESET (desc);
  4841. X      fgets (desc, MAX_LINE - 2, fout);
  4842. X      if (desc [0] != EOS && desc[strlen (desc) - 1] == '\n')
  4843. X        desc[strlen (desc) - 1] = EOS;
  4844. X      continued = FALSE;
  4845. X      if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
  4846. X        desc[strlen (desc) - 1] = EOS,
  4847. X        continued = TRUE;
  4848. X    } while (continued);
  4849. X    if (file[0] != EOS) {
  4850. X      locase (file);
  4851. X      if (!strcmp (stripped_file, file)) {
  4852. X        found = TRUE;
  4853. X        break;
  4854. X      }
  4855. X    }
  4856. X  }
  4857. X  fclose (fout);
  4858. X  if (found) {
  4859. X    if (updatef)
  4860. X      rmfiles (0, 1, &filename, path, no_compression, 1);
  4861. X    else {
  4862. X      fprintf (stderr, "\t- file %s already exists in %s\n\
  4863. X\t- file not archived\n", stripped_file, dirf);
  4864. X      remove_files (dir, filename, count, finbuf, no_compression);
  4865. X      return 0;
  4866. X    }
  4867. X  }
  4868. X  else if (updatef)
  4869. X    fprintf (stderr, "WARNING: %s is not currently archived %s\n",
  4870. X         stripped_file, dirf);
  4871. X  signal (SIGINT, SIG_IGN);
  4872. X  if ((fout = fopen (dirf, "a")) == NULL) {
  4873. X    fprintf (stderr, "Unable to open index %s for update.\nFile %s \
  4874. Xnot archived. Exiting.\n", dirf, filename);
  4875. X    remove_files (dir, filename, count, finbuf, no_compression);
  4876. X    exit (1);
  4877. X  }
  4878. X  fprintf (fout, "%s %ld ", stripped_file, (pure_bin ? -count : count));
  4879. X  for (i = 0; i < count; i++)
  4880. X    fprintf (fout, "%ld ", filesizes[i]);
  4881. X  fprintf (fout, "%s", dir);
  4882. X  if (updatef && comment && text[0] == EOS) {
  4883. X    fprintf (fout, "%s\n", comment);
  4884. X    free ((char *) comment);
  4885. X    comment = NULL;
  4886. X  }
  4887. X  else
  4888. X    fprintf (fout, "%s%s\n", (text[0] != EOS && strcmp (text, " ") ? " " : ""),
  4889. X         (strcmp (text, " ") ? text : ""));
  4890. X  fclose (fout);
  4891. X  signal (SIGINT, SIG_DFL);
  4892. X  return 1;
  4893. X}
  4894. X
  4895. X/*
  4896. X  Remove all parts of the specified file from the specified directory.
  4897. X*/
  4898. X
  4899. Xvoid remove_files (char *dir, char *filename, long int count,
  4900. X           struct stat finbuf, BOOLEAN no_compression)
  4901. X{
  4902. X  char file[10240];
  4903. X  char fout[10240];
  4904. X  struct stat foutbuf;
  4905. X  char yn;
  4906. X  BOOLEAN split = (count > 1 ? 1 : 0);
  4907. X
  4908. X  if (!split) {
  4909. X    sprintf (fout, "%s/%s", dir, filename);
  4910. X    if (!no_compression)
  4911. X      syscom ("uncompress %s.Z  > /dev/null 2>&1 < /dev/null", fout);
  4912. X    if (stat (fout, &foutbuf)) {
  4913. X      printf ("Input file %s may be the same as output file %s/%s.\n\
  4914. XRemove %s/%s [y]? ",
  4915. X          filename, dir, filename, dir, filename);
  4916. X      fflush (stdout);
  4917. X      scanf ("%c", &yn);
  4918. X      if (yn == 'n' || yn == 'N')
  4919. X        return;
  4920. X    }
  4921. X    if ((finbuf.st_ino == foutbuf.st_ino) &&
  4922. X    (finbuf.st_dev == foutbuf.st_dev)) {
  4923. X      printf ("\t- output file matches input: not removed\n");
  4924. X      return;
  4925. X    }
  4926. X  }
  4927. X  while (count) {
  4928. X    RESET (file);
  4929. X    if (split)
  4930. X      sprintf (file, "%s/%s%d", dir, filename, count);
  4931. X    else
  4932. X      sprintf (file, "%s/%s", dir, filename);
  4933. X    unlink (file);
  4934. X    if (!no_compression)
  4935. X      strcat (file, ".Z"),
  4936. X      unlink (file);
  4937. X    --count;
  4938. X  }
  4939. X}
  4940. X
  4941. Xvoid usage ()
  4942. X{
  4943. X  fprintf (stderr, "farch {[-n] [-b | -B] [-s size] \
  4944. X[-d dir] [-p password] [-D 'description'] [-t file] [-u]} | {<-r>} \
  4945. X[-a archive | path-to-archive] [-Z] filename(s)\n");
  4946. X  fprintf (stderr, "-n: do not split input file(s)\n\
  4947. X-b: input files are binary: uuencode (on if -t specified)\n\
  4948. X-B input files are binary: do not uuencode and do not split\n\
  4949. X-s: maximum size of each output file (in kilobytes) -- default %ld\n\
  4950. X-d: actual directory to put output file(s)\n    -- default as specified by -a: %s/<archive>\n\
  4951. X-p: password for a new private archive\n\
  4952. X-D: description of the file to go into the DIR file\n\
  4953. X-t: tar all input files into 'file' and archive that\n\
  4954. X-u: update existing files\n\
  4955. X-a: which archive index to update (subdir of %s)\n    -- \
  4956. Xdefault %s\n\
  4957. X-r: remove the specified file(s) from the archive\n\
  4958. X-Z: turn off file compression\n",
  4959. X(long) DEFAULT_SIZE / 1024, ARCHIVE_DIR, ARCHIVE_DIR, DEFAULT_ARCHIVE);
  4960. X  exit (3);
  4961. X}
  4962. X
  4963. X/*
  4964. X  Archive all files given in 'argv'.
  4965. X*/
  4966. X
  4967. Xvoid do_archive (int optind, int argc, char **argv, char *buf, char *fullpath,
  4968. X             char *archive, char *dir, char *text, long int size,
  4969. X         BOOLEAN bin, BOOLEAN uue, BOOLEAN split, BOOLEAN tar,
  4970. X         BOOLEAN no_compression, BOOLEAN updatef)
  4971. X{
  4972. X  FILE *fin, *fout, *flast;
  4973. X  long int l, count, nread, nchars, total, *filesizes = NULL;
  4974. X  char *leftovers = NULL, *s, *infile = NULL, filename[10240],
  4975. X    compressed[10240];
  4976. X  struct stat sbuf, finbuf;
  4977. X
  4978. X  while (optind < argc) { /* Split and archive each file */
  4979. X
  4980. X    s = argv[optind] + strlen (argv[optind]) - 1;
  4981. X    while (s != argv[optind] && *s == '/')  /* Remove trailing / */
  4982. X      *(s--) = EOS;
  4983. X
  4984. X    if ((fin = fopen (argv[optind], "r")) == NULL) { /* Open file */
  4985. X      fprintf (stderr, "Cannot open file %s for reading.\n", argv[optind]);
  4986. X      goto abort;
  4987. X    }
  4988. X
  4989. X    printf ("%s:\n", argv[optind]);
  4990. X    count = 1;
  4991. X    nchars = 0;
  4992. X
  4993. X    if (infile) /* free previous allocation */
  4994. X      free ((char *) infile);
  4995. X    infile = extract_filename (argv[optind]); /* get filename from path */
  4996. X    locase (infile);
  4997. X    l = strlen (infile);
  4998. X    if (l > 2 && infile [l - 2] == '.' && infile [l - 1] == 'z') {
  4999. X      infile [l - 2] = EOS;
  5000. X      l = strlen (argv[optind]);
  5001. X      argv[optind][l - 2] = EOS;
  5002. X      printf ("\t- uncompressing...\n");
  5003. X      syscom ("uncompress %s > /dev/null 2>&1 < /dev/null", argv[optind]);
  5004. X      fclose (fin);
  5005. X      fin = fopen (argv[optind], "r");
  5006. X    }
  5007. X
  5008. X    stat (argv[optind], &finbuf); /* Get size of input file */
  5009. X    if (bin && uue) /* uuencode */
  5010. X      uuencode (&fin, argv[optind], infile, &finbuf, tar);
  5011. X
  5012. X    if (!split || finbuf.st_size <= size) { /* Not splitting;may have to copy */
  5013. X      fclose (fin);
  5014. X      sprintf (filename, "%s%s%s", (strcmp (dir, "/") ? dir : ""),
  5015. X               ((strcmp (dir, infile) && strcmp (infile, "/")) ? "/" : ""),
  5016. X               infile);
  5017. X
  5018. X      if (updatef)    /* Remove old file */
  5019. X    unlink (filename);
  5020. X
  5021. X      if (bin) { /* Copy (possibly) uue_file to target directory */
  5022. X        if (uue && !stat (filename, &sbuf)) {
  5023. X      fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
  5024. X           filename, argv[optind]);
  5025. X      unlink (uue_file);
  5026. X      free ((char *) uue_file);
  5027. X      goto abort;
  5028. X    }
  5029. X        if (uue && (fout = fopen (filename, "w")) == NULL) { /* Test */
  5030. X          fprintf (stderr, "Cannot write to directory %s; cannot \
  5031. Xproceed with %s\n",
  5032. X                   dir, argv[optind]);
  5033. X      unlink (uue_file);
  5034. X      free ((char *) uue_file);
  5035. X          goto abort;
  5036. X        }
  5037. X    if (uue)
  5038. X          fclose (fout),
  5039. X          syscom ("mv %s %s > /dev/null 2>&1", uue_file, filename);
  5040. X    else if (stat (filename, &sbuf)) { /* File does not exist in target dir */
  5041. X      if ((fout = fopen (filename, "w")) == NULL) { /* Test */
  5042. X        fprintf (stderr, "Cannot write to directory %s; cannot \
  5043. Xproceed with %s\n",
  5044. X             dir, argv[optind]);
  5045. X        goto abort;
  5046. X      }
  5047. X      fclose (fout);
  5048. X      syscom ("cp %s %s > /dev/null 2>&1", argv[optind], filename);
  5049. X    }
  5050. X      }
  5051. X      else if (stat (filename, &sbuf)) { /* File does not exist in target dir */
  5052. X        if ((fout = fopen (filename, "w")) == NULL) {
  5053. X          fprintf (stderr, "Cannot write to directory %s; cannot \
  5054. Xproceed with %s\n",
  5055. X                   dir, argv[optind]);
  5056. X          goto abort;
  5057. X        }
  5058. X        fclose (fout);
  5059. X        syscom ("cp %s %s > /dev/null 2>&1", argv[optind], filename);
  5060. X      }
  5061. X      else {
  5062. X    fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
  5063. X         filename, argv[optind]);
  5064. X    goto abort;
  5065. X      }
  5066. X
  5067. X      if (!no_compression) {
  5068. X    sprintf (compressed, "%s.Z", filename);
  5069. X    if (updatef)
  5070. X      unlink (compressed);
  5071. X    else if (!stat (compressed, &sbuf)) {
  5072. X      fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
  5073. X           compressed, argv[optind]);
  5074. X      if (bin && uue)
  5075. X        unlink (uue_file),
  5076. X        free ((char *) uue_file);
  5077. X      goto abort;
  5078. X    }
  5079. X      }
  5080. X
  5081. X      filesizes = (long int *) malloc (sizeof (long int));
  5082. X      *filesizes = (long int) finbuf.st_size;
  5083. X      if (!no_compression)
  5084. X    syscom ("compress %s > /dev/null 2>&1 < /dev/null", filename);
  5085. X      chmod (filename, 0644 & (0644 ^ otoi (archives_mask)));
  5086. X      if (update (fullpath, infile, 1, filesizes, dir, text, finbuf,bin & !uue,
  5087. X          no_compression, updatef))
  5088. X        printf ("\t- file not split, %s\n\t- archived in %s\n\t- directory: %s\n",
  5089. X                (no_compression ? "not compressed" : "compressed"),
  5090. X        archive, dir);
  5091. X      free ((long int *) filesizes);
  5092. X      filesizes = NULL;
  5093. X    }
  5094. X    else { /* Split file */
  5095. X      while (!feof (fin)) {
  5096. X        sprintf (filename, "%s%s%s%d", (strcmp (dir, "/") ? dir : ""),
  5097. X                 ((strcmp (dir, infile) && strcmp (infile, "/")) ? "/" : ""),
  5098. X                 infile, count);
  5099. X
  5100. X    if (updatef)
  5101. X      unlink (filename);
  5102. X        else if (!stat (filename, &sbuf)) {
  5103. X          fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
  5104. X                   filename, argv[optind]);
  5105. X      if (bin)
  5106. X        unlink (uue_file),
  5107. X        free ((char *) uue_file);
  5108. X          fout = (FILE *) -1;
  5109. X          break;
  5110. X        }
  5111. X        if ((fout = fopen (filename, "w")) == NULL) {
  5112. X          fprintf (stderr, "Cannot write to directory %s; cannot proceed \
  5113. Xwith %s\n",
  5114. X                   dir, argv[optind]);
  5115. X          fout = (FILE *) -1;
  5116. X          break;
  5117. X        }
  5118. X    chmod (filename, 0644 & (0644 ^ otoi (archives_mask)));
  5119. X
  5120. X        total = 0;  /* Do the actual splitting */
  5121. X        total += fwrite (leftovers, sizeof (char), nchars, fout);
  5122. X        nread = fread (buf, sizeof (char), size - nchars, fin);
  5123. X        if (nchars)
  5124. X          free ((char *) leftovers);
  5125. X        s = buf + nread - (nread > 0 ? 1 : 0);
  5126. X        nchars = 0;
  5127. X        while (s != buf && *s != '\n') /* Look for first \n from the end */
  5128. X          ++nchars,
  5129. X          --s;
  5130. X        if (s == buf) /* No new line found; write as is */
  5131. X          nchars = 0;
  5132. X        nread -= nchars;
  5133. X        leftovers = (char *) malloc (nchars * sizeof (char));
  5134. X        strncpy (leftovers, ++s, nchars); /* Copy anything after \n */
  5135. X        total += fwrite (buf, sizeof (char), nread, fout);
  5136. X        fclose (fout);
  5137. X
  5138. X        if (total == 0)
  5139. X          unlink (filename);
  5140. X        else { /* OK, compress */
  5141. X      if (!no_compression) {
  5142. X        sprintf (compressed, "%s.Z", filename);
  5143. X        if (updatef)
  5144. X          unlink (compressed);
  5145. X        else if (!stat (compressed, &sbuf)) {
  5146. X          fprintf (stderr, "Output file %s exists; cannot proceed with %s\n",
  5147. X               compressed, argv[optind]);
  5148. X          if (bin)
  5149. X        unlink (uue_file),
  5150. X        free ((char *) uue_file);
  5151. X          unlink (filename);
  5152. X          goto abort;
  5153. X        }
  5154. X      }
  5155. X      stat (filename, &sbuf);
  5156. X      filesizes = (long int *)
  5157. X        (filesizes ?
  5158. X          (realloc ((long int *) filesizes, count * sizeof (long int))) :
  5159. X          (malloc (count * sizeof (long int))));
  5160. X      *(filesizes + (count - 1)) = (long int) sbuf.st_size;
  5161. X      if (!no_compression)
  5162. X        syscom ("compress %s > /dev/null 2>&1 < /dev/null", filename);
  5163. X      ++count; /* Always one ahead */
  5164. X    }
  5165. X      }
  5166. X
  5167. X      fclose (fin);
  5168. X      if (bin)
  5169. X        unlink (uue_file),
  5170. X    free ((char *) uue_file);
  5171. X      if (nchars) /* write any leftovers */
  5172. X        flast = fopen (filename, "a"),
  5173. X        fwrite (leftovers, sizeof (char), nchars, flast),
  5174. X        fclose (flast),
  5175. X        free ((char *) leftovers),
  5176. X    stat (filename, &sbuf),
  5177. X    *(filesizes + (count - 2)) = (long int) sbuf.st_size;
  5178. X
  5179. X      if (fout != (FILE *) -1) { /* Splitting successful, update DIR file */
  5180. X        if (update (fullpath, infile, count - 1, filesizes, dir, text, finbuf,
  5181. X        bin & !uue, no_compression, updatef))
  5182. X          printf ("\t- file split in %ld %scompressed parts\n\t- archived in %s\n\t\
  5183. X- directory: %s\n",
  5184. X          (long) count - 1, 
  5185. X                  (no_compression ? "un" : ""), 
  5186. X          archive, dir);
  5187. X    free ((long int *) filesizes);
  5188. X    filesizes = NULL;
  5189. X      }
  5190. X    }
  5191. X    abort:
  5192. X    ++optind;
  5193. X  }
  5194. X}
  5195. X
  5196. X/*
  5197. X  Get archive to update.
  5198. X*/
  5199. X
  5200. Xint get_archive (char **archive, char *fullpath, char *password,
  5201. X         BOOLEAN remove_file)
  5202. X{
  5203. X  FILE *master;
  5204. X  char indexf[10240], line[10240], cur_archive[10240], arch[10240], dirf[10240],
  5205. X  error [10240], *slash;
  5206. X  char original[10240];
  5207. X  BOOLEAN found = FALSE;
  5208. X
  5209. X  if (!*archive)
  5210. X    *archive = DEFAULT_ARCHIVE;
  5211. X  strcpy (cur_archive, (char *) *archive);
  5212. X  strcpy (original, *archive);
  5213. X  if ((slash = strchr (cur_archive, '/')))
  5214. X    *slash = EOS;
  5215. X  sprintf (indexf, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
  5216. X  while (*archive[0] != EOS) { /* Check all archives specified */
  5217. X    if ((master = fopen (indexf, "r")) == NULL) {
  5218. X      fprintf (stderr, "Sorry, no master index found.\n");
  5219. X      return 0;
  5220. X    }
  5221. X    found = FALSE;
  5222. X    while (!feof (master)) { /* Look at the current index for fullpath */
  5223. X      indexf[0] = arch[0] = RESET (line);
  5224. X      fgets (line, MAX_LINE - 2, master);
  5225. X      if (line[0] != EOS) {
  5226. X        sscanf (line, "%s %s\n", arch, indexf);
  5227. X        locase (arch);
  5228. X        if (!strcmp (arch, cur_archive)) {
  5229. X          found = TRUE;
  5230. X          break;
  5231. X        }
  5232. X      }
  5233. X    }
  5234. X    fclose (master);
  5235. X    if (!found && remove_file) {
  5236. X      fprintf (stderr, "%s: not a valid archive or path.\n", cur_archive);
  5237. X      return 0;
  5238. X    }
  5239. X    sprintf (dirf, "%s/%s/%s", ARCHIVE_DIR, original, DIRF);
  5240. X    if (!found) { 
  5241. X      sprintf (dirf, "%s/%s/%s", ARCHIVE_DIR, original, DIRF);
  5242. X      printf ("New archive %s; creating all directories and necessary files\n",
  5243. X          original);
  5244. X      if (!make_indexes (dirf, original, password, error, "077")) {
  5245. X    fprintf (stderr, "%s", error);
  5246. X    return 0;
  5247. X      }
  5248. X      sprintf (indexf, "%s/%s", ARCHIVE_DIR, original);
  5249. X    }
  5250. X    if ((slash = strchr (*archive, '/')))
  5251. X      sprintf (*archive, "%s", slash + 1); /* Move down the path */
  5252. X    else
  5253. X      sprintf (*archive, "%s", *archive + strlen (cur_archive));
  5254. X    strcpy (cur_archive, *archive);
  5255. X    if ((slash = strchr (cur_archive, '/')))
  5256. X      *slash = EOS;
  5257. X    if (cur_archive[0] != EOS)
  5258. X      sprintf (indexf, "%s/%s", indexf, INDEX);
  5259. X  }
  5260. X  strcpy (fullpath, indexf);
  5261. X  strcpy (*archive, original);
  5262. X  return 1;
  5263. X}
  5264. X
  5265. X/*
  5266. X  Get output directory.
  5267. X*/
  5268. X
  5269. Xint get_dir (char *newdir, char **dir, char *fullpath)
  5270. X{
  5271. X  char *s;
  5272. X  char msg [MAX_LINE];
  5273. X  struct stat sbuf;
  5274. X
  5275. X  free ((char *) *dir);
  5276. X  if (!newdir)
  5277. X    *dir = (char *) malloc ((strlen (fullpath) + 1) * sizeof (char)),
  5278. X    sprintf (*dir, "%s", fullpath);
  5279. X  else {
  5280. X    *dir = (char *) malloc ((strlen (newdir) + 1) * sizeof (char));
  5281. X    sprintf (*dir, "%s", newdir);
  5282. X    s = *dir + strlen (*dir) - 1;
  5283. X    while (s != *dir && *s == '/')
  5284. X      *(s--) = EOS;
  5285. X  }
  5286. X  if (stat (*dir, &sbuf)) {
  5287. X    if (!mkdir1 (*dir, msg, "077")) {
  5288. X      fprintf (stderr, "Unable to create new directory %s\n%s", *dir, msg);
  5289. X      return 0;
  5290. X    }
  5291. X    printf ("Creating new directory %s\n", *dir);
  5292. X  }
  5293. X  return 1;
  5294. X}
  5295. X
  5296. X/*
  5297. X  Required to avoid undefined symbols.
  5298. X*/
  5299. X
  5300. Xint gexit (int exitcode)
  5301. X{
  5302. X  exit (exitcode);
  5303. X}
  5304. *-*-END-of-src/farch.c-*-*
  5305. echo x - src/fio.c
  5306. sed 's/^X//' >src/fio.c <<'*-*-END-of-src/fio.c-*-*'
  5307. X#include <stdio.h>
  5308. X#include <string.h>
  5309. X#include <sys/types.h>
  5310. X#include <sys/stat.h>
  5311. X#include <sys/file.h>
  5312. X#include <fcntl.h>
  5313. X#include <errno.h>
  5314. X# ifdef unknown_port
  5315. Xextern int errno;
  5316. X# endif
  5317. X#if !defined (stellar) && !defined (unknown_port)
  5318. X# include <time.h>
  5319. X#endif
  5320. X#include <sys/time.h>
  5321. X#if !defined (__NeXT__) && !defined (stardent) && !defined (unknown_port)
  5322. X# include <utime.h>      /* not in NeXT OS 2.1; Under 3.0, included by sys/types.h */
  5323. X#else
  5324. X# include "next.h"
  5325. X#endif
  5326. X#include "defs.h"
  5327. X
  5328. X/*
  5329. X  Speed up the system by not forking off processes for things that
  5330. X  can be done with a syscall or two (or 50 for that matter).
  5331. X
  5332. X  Copyright 1993
  5333. X  Kenneth Lorber (keni@oasys.dt.navy.mil)
  5334. X  David Taylor Model Basin
  5335. X  Carderock Division, Naval Surface Warfare Center
  5336. X
  5337. X  This code may be freely redistributed.
  5338. X
  5339. X  [tasos: the code has been expanded to use the ULISTPROC_UMASK environment
  5340. X  variable, fixed spacing to match the rest of the system and some function
  5341. X  prototyping problems; also altered syntax/use of utime() for NeXT hosts,
  5342. X  and removed const declarations which are not removed by the unproto package,
  5343. X  plus some bug fixing as well]
  5344. X*/
  5345. X
  5346. X#ifdef __STDC__
  5347. X# include <stdarg.h>
  5348. Xchar *tsprintf (char *, ...);
  5349. X#else
  5350. X# include <varargs.h>
  5351. Xchar *tsprintf ();
  5352. X#endif
  5353. X
  5354. Xextern char *extract_filename (char *);
  5355. Xextern void shrink (char *);
  5356. Xextern int otoi (char *);
  5357. Xextern char *getenv ();
  5358. X
  5359. Xtypedef enum append { NOAPPEND, APPEND } _append;
  5360. Xstatic int echo_internal (char *, char *, _append);
  5361. Xstatic int cat_internal (char *, char *, _append);
  5362. Xstatic int log_warn (char *);
  5363. X
  5364. Xint echo (char *, char *);
  5365. Xint echo_append (char *, char *);
  5366. Xint mv (char *, char *);
  5367. Xint cp (char *, char *);
  5368. Xint cat (char *, char *);
  5369. Xint cat_append (char *, char *);
  5370. Xint touch (char *);
  5371. X
  5372. Xint echo (char *text, char *file)
  5373. X{
  5374. X  return echo_internal (text, file, NOAPPEND);
  5375. X}
  5376. X
  5377. Xint echo_append (char *text, char *file)
  5378. X{
  5379. X  return echo_internal (text, file, APPEND);
  5380. X}
  5381. X
  5382. Xstatic int echo_internal (char *text, char *file, _append append)
  5383. X{
  5384. X  int d;
  5385. X  long int len;
  5386. X  char *mask;
  5387. X
  5388. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  5389. X    umask (otoi (mask));
  5390. X  else
  5391. X    mask = "066",
  5392. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  5393. X  if (append == APPEND)
  5394. X    d = open (file, O_CREAT|O_APPEND|O_WRONLY, 0666 & (0666 ^ otoi (mask)));
  5395. X  else
  5396. X    d = open (file, O_CREAT|O_TRUNC|O_WRONLY, 0666 & (0666 ^ otoi (mask)));
  5397. X  if (d == -1) {
  5398. X    log_warn (tsprintf ("echo: open: %s", file));
  5399. X    return 1;
  5400. X  }
  5401. X
  5402. X  len = strlen (text);
  5403. X  if (len != write (d, text, len))
  5404. X    goto write_error;
  5405. X  if (1 != write (d, "\n", 1)) {
  5406. X  write_error:
  5407. X    log_warn (tsprintf ("echo: write: %s", file));
  5408. X    close (d);
  5409. X    return 1;
  5410. X  }
  5411. X    
  5412. X  if (close (d)) {
  5413. X    log_warn (tsprintf ("echo: close: %s", file));
  5414. X    return 1;
  5415. X  }
  5416. X  return 0;
  5417. X}
  5418. X
  5419. Xint mv (char *oldfile, char *newfile)
  5420. X{
  5421. X  (void) unlink (newfile);
  5422. X  errno = 0;
  5423. X  if (link (oldfile, newfile)) {
  5424. X    if (errno == EXDEV) {
  5425. X      if (cp (oldfile, newfile))
  5426. X    return 1; /* can't copy either */
  5427. X    }
  5428. X    else {
  5429. X      log_warn (tsprintf ("mv: %s %s", oldfile, newfile));
  5430. X      return 0;
  5431. X    }
  5432. X  }
  5433. X  unlink (oldfile);
  5434. X  return 0;
  5435. X}
  5436. X
  5437. Xint cp (char *oldfile, char *newfile)
  5438. X{
  5439. X  struct stat oldstat, newstat;
  5440. X  int oldfd, newfd;
  5441. X  char *newname, *buffer, *mask, buf[256];
  5442. X  long int size;
  5443. X
  5444. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  5445. X    umask (otoi (mask));
  5446. X  else
  5447. X    mask = "066",
  5448. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  5449. X  oldfd = open (oldfile, O_RDONLY, 0);
  5450. X  if (oldfd < 0) {
  5451. X    log_warn (tsprintf ("cp: open: %s", oldfile));
  5452. X    return 1;
  5453. X  }
  5454. X  if (fstat (oldfd, &oldstat)) {
  5455. X    log_warn (tsprintf ("cp: fstat: %s", oldfile));
  5456. X    close (oldfd);
  5457. X    return 1;
  5458. X  }
  5459. X
  5460. X  newname = newfile;
  5461. X  if (!stat (newfile, &newstat)) {
  5462. X    if (newstat.st_mode & S_IFDIR) {
  5463. X      char *s;
  5464. X      sprintf (buf, "%s/%s", newfile, (s = extract_filename (oldfile)));
  5465. X      newname = buf;
  5466. X      free ((char *) s);
  5467. X    }
  5468. X  }
  5469. X
  5470. X  newfd = open (newname, O_WRONLY|O_TRUNC|O_CREAT,
  5471. X        oldstat.st_mode & (0666 ^ otoi (mask)));
  5472. X  if (newfd < 0) {
  5473. X    log_warn (tsprintf ("cp: open: %s", newname));
  5474. X    close (oldfd);
  5475. X    return 1;
  5476. X  }
  5477. X
  5478. X  buffer = (char *) malloc (65536 * sizeof (char));
  5479. X  while ((size = read (oldfd, buffer, 65536)) > 0) {
  5480. X    if (size != write (newfd, buffer, size)) {
  5481. X      log_warn (tsprintf ("cp: write %s", newname));
  5482. X      free ((char *) buffer);
  5483. X      close (oldfd);
  5484. X      close (newfd);
  5485. X      return 1;
  5486. X    }
  5487. X  }
  5488. X  free ((char *) buffer);
  5489. X  if (size < 0) {
  5490. X    log_warn (tsprintf ("cp: read: %s", oldfile));
  5491. X    close (oldfd);
  5492. X    close (newfd);
  5493. X    return 1;
  5494. X  }
  5495. X  close (oldfd);
  5496. X  close (newfd);
  5497. X  return 0;
  5498. X}
  5499. X
  5500. Xint cat (char *srcfile, char *dstfile)
  5501. X{
  5502. X  return cat_internal (srcfile, dstfile, NOAPPEND);
  5503. X}
  5504. X
  5505. Xint cat_append (char *srcfile, char *dstfile)
  5506. X{
  5507. X  return cat_internal (srcfile, dstfile, APPEND);
  5508. X}
  5509. X
  5510. Xstatic int cat_internal (char *srcfile, char *dstfile, _append append)
  5511. X{
  5512. X  struct stat srcstat;
  5513. X  int srcfd, dstfd;
  5514. X  char *buffer, *mask;
  5515. X  long int size;
  5516. X
  5517. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  5518. X    umask (otoi (mask));
  5519. X  else
  5520. X    mask = "066",
  5521. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  5522. X  srcfd = open (srcfile, O_RDONLY, 0);
  5523. X  if (srcfd < 0) {
  5524. X    log_warn (tsprintf ("cat: open: %s", srcfile));
  5525. X    return 1;
  5526. X  }
  5527. X  if (fstat (srcfd, &srcstat)) {
  5528. X    log_warn (tsprintf ("cat: fstat: %s", srcfile));
  5529. X    close (srcfd);
  5530. X    return 1;
  5531. X  }
  5532. X
  5533. X  if (append == APPEND)
  5534. X    dstfd = open (dstfile, O_WRONLY|O_APPEND|O_CREAT,
  5535. X          srcstat.st_mode & (0666 ^ otoi (mask)));
  5536. X  else
  5537. X    dstfd = open (dstfile, O_WRONLY|O_TRUNC|O_CREAT,
  5538. X          srcstat.st_mode & (0666 ^ otoi (mask)));
  5539. X  if (dstfd < 0) {
  5540. X    log_warn (tsprintf ("cat: open: %s", dstfile));
  5541. X    close (srcfd);
  5542. X    return 1;
  5543. X  }
  5544. X
  5545. X  buffer = (char *) malloc (65536 * sizeof (char));
  5546. X  while ((size = read (srcfd, buffer, 65536)) > 0) {
  5547. X    if (size != write (dstfd, buffer, size)) {
  5548. X      log_warn (tsprintf ("cat: write: %s", dstfile));
  5549. X      free ((char *) buffer);
  5550. X      close (srcfd);
  5551. X      close (dstfd);
  5552. X      return 1;
  5553. X    }
  5554. X  }
  5555. X  free ((char *) buffer);
  5556. X  if (size < 0) {
  5557. X    log_warn (tsprintf ("cat: read: %s", srcfile));
  5558. X    close (srcfd);
  5559. X    close (dstfd);
  5560. X    return 1;
  5561. X  }
  5562. X  close (srcfd);
  5563. X  close (dstfd);
  5564. X  return 0;
  5565. X}
  5566. X
  5567. Xint touch (char *file)
  5568. X{
  5569. X  char *mask;
  5570. X  int d;
  5571. X#ifdef __NeXT__
  5572. X  struct timeval tvp[2];
  5573. X#elif defined (i386)
  5574. X  struct utimbuf utimest;
  5575. X#endif
  5576. X
  5577. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  5578. X    umask (otoi (mask));
  5579. X  else
  5580. X    mask = "066",
  5581. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  5582. X  d = open (file, O_CREAT|O_EXCL, 0666 & (0666 ^ otoi (mask)));
  5583. X#ifdef __NeXT__
  5584. X  tvp[0].tv_sec = tvp[0].tv_usec = tvp[1].tv_sec = tvp[1].tv_usec = 0;
  5585. X#elif defined (i386)
  5586. X  utimest.actime = utimest.modtime = 0;
  5587. X#endif
  5588. X
  5589. X  if (d < 0) {
  5590. X    if (errno != EEXIST) {
  5591. X      log_warn (tsprintf ("touch: open: %s", file));
  5592. X      return 1;
  5593. X    }
  5594. X  }
  5595. X  else {
  5596. X    close (d);
  5597. X    return 0;
  5598. X  }
  5599. X#ifdef __NeXT__
  5600. X  if (utime (file, tvp)) {
  5601. X#elif defined (i386) || defined (linux)
  5602. X  if (utime (file, &utimest)) {
  5603. X#else
  5604. X  if (utime (file, NULL)) {
  5605. X#endif
  5606. X    log_warn (tsprintf ("touch: utime: %s",file));
  5607. X    return 1;
  5608. X  }
  5609. X  return 0;
  5610. X}
  5611. X
  5612. X/* support routines */
  5613. X
  5614. X#ifdef __STDC__
  5615. Xchar *tsprintf (char *control, ...)
  5616. X#else
  5617. Xchar *tsprintf (control, va_alist)
  5618. Xchar *control;
  5619. Xva_dcl
  5620. X#endif
  5621. X{
  5622. X  static char command [10240];
  5623. X  va_list ap;
  5624. X
  5625. X#ifdef __STDC__
  5626. X  va_start (ap, control);
  5627. X#else
  5628. X  va_start (ap);
  5629. X#endif
  5630. X  RESET (command);
  5631. X  vsprintf (command, control, ap);
  5632. X  va_end (ap);
  5633. X  return command;
  5634. X}
  5635. X
  5636. Xstatic int log_warn (char *command)
  5637. X{
  5638. X  extern BOOLEAN tty_echo;
  5639. X  FILE *f;
  5640. X  struct tm *t;
  5641. X#ifdef ultrix
  5642. X  time_t time_is = 0;
  5643. X#else
  5644. X  long int time_is = 0;
  5645. X#endif
  5646. X  int _errno = errno;
  5647. X
  5648. X  if ((f = fopen (WARNING, "a")) != NULL)
  5649. X    fprintf (f, "\nWARNING: System call errno %d: %s\n", _errno, command),
  5650. X    time (&time_is),
  5651. X    t = localtime (&time_is),
  5652. X    fprintf (f, "Time/Date: %2d:%.2d:%.2d, %2d/%.2d/%2d\n",
  5653. X         t->tm_hour, t->tm_min, t->tm_sec, t->tm_mon + 1, t->tm_mday,
  5654. X         t->tm_year),
  5655. X    fclose (f);
  5656. X  if (tty_echo)
  5657. X    printf ("\nWARNING: System call errno %d: %s\n", _errno, command);
  5658. X}
  5659. *-*-END-of-src/fio.c-*-*
  5660. echo x - src/fwin.c
  5661. sed 's/^X//' >src/fwin.c <<'*-*-END-of-src/fwin.c-*-*'
  5662. X/*
  5663. X  ----------------------------------------------------------------------------
  5664. X  |                FILE WINDOW                     |
  5665. X  |                                         |
  5666. X  |                             Version 1.0                     |
  5667. X  |                                                                          |
  5668. X  |                (or, when Computer Science gets to you)                   |
  5669. X  |                                                                          |
  5670. X  |                    Written by Anastasios Kotsikonas                      |
  5671. X  |                           (tasos@cs.bu.edu)                              |
  5672. X  |                                                                          |
  5673. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  5674. X  | whole and not in parts, as long as you do not remove or alter the author |
  5675. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  5676. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  5677. X  | provided for your personal use, you may not alter the functions          |
  5678. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  5679. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  5680. X  | any changes you may have made. No part of the source code bearing a         |
  5681. X  | copyright notice can be included in commercial software systems without  |
  5682. X  | written permission by the author.                         |
  5683. X  | By using this software you are bound by this agreement.                  |
  5684. X  | This software comes with no warranties and cannot be sold for profit.    |
  5685. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  5686. X  | files when distributing this software.                                   |
  5687. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  5688. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  5689. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  5690. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  5691. X  | (ii).                                                                    |
  5692. X  ----------------------------------------------------------------------------
  5693. X
  5694. X  Copy a window of the input (stdin) to output (stdout); the window is defined
  5695. X  as an offset from the beginning and a byte count. If no byte count is defined
  5696. X  then MAXINT is used.
  5697. X
  5698. X  COMMAND LINE OPTIONS:
  5699. X    -o: Set the offset from the beginning of the file (default 0).
  5700. X    -b: Set the byte count (default MAXINT).
  5701. X    -n: Pad with new line at the end if not there.
  5702. X*/
  5703. X
  5704. X#include <stdio.h>
  5705. X#include <sys/types.h>
  5706. X#if !defined (__NeXT__) && !defined (NetBSD)
  5707. X# ifndef unknown_port
  5708. X#  include <unistd.h>
  5709. X# endif
  5710. X# if !defined (sequent) && !defined (__convex__) && !defined (apollo) && \
  5711. X  !defined (unknown_port)
  5712. X#  include <values.h>
  5713. X# endif
  5714. X#else
  5715. X# include <libc.h>
  5716. X#endif
  5717. X
  5718. X#ifndef __NeXT__
  5719. Xextern long int atol (char *);
  5720. X#else
  5721. Xextern long int atol (const char *);
  5722. X#endif
  5723. X
  5724. X#define BUFFSIZ        8192
  5725. X#ifndef MAXINT
  5726. X# define MAXINT        0x7FFFFFFF    /* assumes 32-bit hardware */
  5727. X#endif
  5728. X
  5729. Xmain (int argc, char **argv)
  5730. X{
  5731. X  char *options = "o:b:n", last_byte;
  5732. X  long int offset = 0, bytes = MAXINT, bytes_read = 0, total_bytes = 0;
  5733. X  int pad_with_newline = 0, c;
  5734. X  char buf [BUFFSIZ];
  5735. X  extern char *optarg;
  5736. X
  5737. X  while ((c = getopt (argc, argv, options)) != EOF)
  5738. X    switch ((char) c) {
  5739. X    case 'o':
  5740. X      if ((offset = atol (optarg)) < 0)
  5741. X    fprintf (stderr, "Negative offset (%ld) not allowed.\n", offset),
  5742. X    exit (3);
  5743. X      break;
  5744. X    case 'b':
  5745. X      if ((bytes = atol (optarg)) < 0)
  5746. X    fprintf (stderr, "Negative number of bytes to output (%ld) not allowed.\n", bytes),
  5747. X    exit (3);
  5748. X      break;
  5749. X    case 'n': pad_with_newline = 1; break;
  5750. X    default: 
  5751. X      printf ("Usage: %s [-n] [-o offset] [-b bytes]\n", argv[0]);
  5752. X      exit (3);
  5753. X    }
  5754. X
  5755. X  /* Skip to offset */
  5756. X  while ((bytes_read = read (fileno (stdin), buf, BUFFSIZ)) > 0) {
  5757. X    total_bytes += bytes_read;
  5758. X    if (total_bytes >= offset)
  5759. X      break;
  5760. X  }
  5761. X  if (total_bytes >= offset && bytes_read > 0) {
  5762. X    last_byte = 
  5763. X      buf[bytes_read - total_bytes + offset +
  5764. X      (total_bytes - offset <= bytes ? total_bytes - offset : bytes) - 1];
  5765. X    total_bytes = 
  5766. X      write (fileno (stdout),
  5767. X         &buf[bytes_read - total_bytes + offset],
  5768. X         (total_bytes - offset <= bytes ? total_bytes - offset : bytes));
  5769. X    if (total_bytes < bytes)
  5770. X      while ((bytes_read = read (fileno (stdin), buf, BUFFSIZ)) > 0) {
  5771. X    total_bytes += bytes_read;
  5772. X    write (fileno (stdout), buf,
  5773. X           (total_bytes <= bytes ?
  5774. X        bytes_read :
  5775. X        bytes_read - total_bytes + bytes));
  5776. X    last_byte = buf [(total_bytes <= bytes ? bytes_read :
  5777. X              bytes_read - total_bytes + bytes) - 1];
  5778. X    if (total_bytes >= bytes)
  5779. X      break;
  5780. X      }
  5781. X  }
  5782. X  if (pad_with_newline && last_byte != '\n')
  5783. X    write (fileno (stdout), "\n", 1);
  5784. X  fclose (stdout);
  5785. X  if (bytes_read > 0)
  5786. X    while (read (fileno (stdin), buf, BUFFSIZ) > 0);
  5787. X  exit (0);
  5788. X}
  5789. *-*-END-of-src/fwin.c-*-*
  5790. echo x - src/ilp.c
  5791. sed 's/^X//' >src/ilp.c <<'*-*-END-of-src/ilp.c-*-*'
  5792. X/*
  5793. X  ----------------------------------------------------------------------------
  5794. X  |                   INTERACTIVE LISTPROCESSOR CLIENT                      |
  5795. X  |                                         |
  5796. X  |                  Version 2.1                     |
  5797. X  |                                         |
  5798. X  |                (or, when Computer Science gets to you)                   |
  5799. X  |                                         |
  5800. X  |               Written by Anastasios Kotsikonas                      |
  5801. X  |                      (tasos@cs.bu.edu)                          |
  5802. X  |                                         |
  5803. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  5804. X  | whole and not in parts, as long as you do not remove or alter the author |
  5805. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  5806. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  5807. X  | provided for your personal use, you may not alter the functions          |
  5808. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  5809. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  5810. X  | any changes you may have made. No part of the source code bearing a         |
  5811. X  | copyright notice can be included in commercial software systems without  |
  5812. X  | written permission by the author.                         |
  5813. X  | By using this software you are bound by this agreement.             |
  5814. X  | This software comes with no warranties and cannot be sold for profit.    |
  5815. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  5816. X  | files when distributing this software.                                   |
  5817. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  5818. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  5819. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  5820. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  5821. X  | (ii).                                                                    |
  5822. X  ----------------------------------------------------------------------------
  5823. X
  5824. X  This program is to be used for connecting to an interactive ListProcessor
  5825. X  server (version 6.0 and up). The following files are required:
  5826. X
  5827. X  ilp.c (this file)
  5828. X  ilp.h
  5829. X  ilpp.h (definition of the Interactive ListProcessor Protocol)
  5830. X  makefile
  5831. X
  5832. X  Usage: ilp [-v] [-t timeout] [-b buffer-size in K] <host> [port]
  5833. X
  5834. X  To connect to a host you may specify its name or IP address. The default
  5835. X  port is 372; another port may be specified as an extra argument. To echo
  5836. X  server responses to client requests, use the -v flag.
  5837. X
  5838. X  The default time out for a server response is 180 seconds; to reset
  5839. X  use the -t flag. The default socket buffer size is 8K; to reset use
  5840. X  the -b flag (the argument specifies kilobytes).
  5841. X
  5842. X  This client is to be used as a model and better ones can certainly be
  5843. X  written.
  5844. X
  5845. X  SCO  system should compile with -Dsco.
  5846. X
  5847. X  Refer to the man page for more information on how to use this program.
  5848. X
  5849. X  Compile with -DNO_ABORT_OP if compiler errors are generated.
  5850. X
  5851. X  Version history:
  5852. X  1.0: original version -- no abort operation
  5853. X  2.0: abort operation implemented -- requires server support also, versions
  5854. X       6.0a (July 1 1993) or later; better shell control
  5855. X  2.1: reduced CPU usage
  5856. X*/
  5857. X
  5858. X#include <signal.h>
  5859. X#include "defs.h"
  5860. X#undef     NSIG
  5861. X#ifdef GO_INTERACTIVE
  5862. X# include <stdio.h>
  5863. X# include <sys/types.h>
  5864. X# include <string.h>
  5865. X# if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
  5866. X && !defined (sequent) && !defined (unknown_port)
  5867. X# include <malloc.h>
  5868. X# endif
  5869. X# ifndef unknown_port
  5870. X#  ifndef __NeXT__
  5871. X#   include <unistd.h>
  5872. X#  else
  5873. X#   include <libc.h>
  5874. X#  endif
  5875. X# endif
  5876. X# if defined (stardent) || defined (stellar) || defined (titan)
  5877. X#  include <rpc/types.h>
  5878. X# endif
  5879. X# include <sys/stat.h>
  5880. X# include <fcntl.h>
  5881. X# include <errno.h>
  5882. X# ifdef unknown_port
  5883. Xextern int errno;
  5884. X# endif
  5885. X# include <sys/socket.h>
  5886. X# include <netinet/in.h>
  5887. X# include <netdb.h>
  5888. X# include <sys/file.h>
  5889. X# include <sys/ioctl.h>
  5890. X# if defined (sco) || defined (M_XENIX) || defined (M_UNIX)
  5891. X#  include <sys/stropts.h>
  5892. X# endif
  5893. X# ifndef NO_ABORT_OP
  5894. X#  if defined (sgi) || defined (__sgi)
  5895. X#   include <net/soioctl.h>
  5896. X#  elif !defined (hpux) && !defined (__hpux) && !defined (ultrix) && \
  5897. X    !defined (mips) && !defined (__mips) && !defined (titan) && \
  5898. X    !defined (__DGUX__) && !defined (stellar) && !defined (_AIX) && \
  5899. X    !defined (i386) && !defined (__NeXT__) && !defined (__convex__) && \
  5900. X    !defined (titan) && !defined (M_UNIX) && !defined (M_XENIX) && \
  5901. X    !defined (xenix) && !defined (sco) && !defined (apollo) && \
  5902. X    !defined (__osf__) && !defined (sequent)
  5903. X#   include <sys/sockio.h>
  5904. X#  endif
  5905. X# endif
  5906. X# if (defined (sco) || defined (M_XENIX) || defined (M_UNIX)) && \
  5907. X  defined (HAVE_SELECT_H)
  5908. X#  include <sys/times.h>
  5909. X# else
  5910. X#  include <sys/time.h>
  5911. X# endif
  5912. X# ifdef HAVE_SELECT_H
  5913. X#  include <sys/select.h>
  5914. X# endif
  5915. X# ifdef HAVE_ULIMIT_H
  5916. X#  include <ulimit.h>
  5917. X# endif
  5918. X# include "ilp.h"
  5919. X
  5920. X# ifndef UL_GDESLIM
  5921. X#  define UL_GDESLIM    4
  5922. X# endif
  5923. X# ifndef FD_SET          /* for 4.2BSD */
  5924. X#  define FD_SETSIZE      (sizeof(fd_set) * 8)
  5925. X#  define FD_SET(n, p)    (((fd_set *) (p))->fds_bits[0] |= (1 << ((n) % 32)))
  5926. X#  define FD_CLR(n, p)    (((fd_set *) (p))->fds_bits[0] &= ~(1 << ((n) % 32)))
  5927. X#  define FD_ISSET(n, p)  (((fd_set *) (p))->fds_bits[0] & (1 << ((n) % 32)))
  5928. X#  define FD_ZERO(p)      memset ((char *)(p), '\0', sizeof(*(p)))
  5929. X# endif
  5930. X
  5931. X# ifndef __NeXT__
  5932. Xextern    long int atoi (char *);
  5933. X# else
  5934. Xextern    int atoi (const char *);
  5935. X# endif
  5936. Xextern  int optind;
  5937. X# if !defined (hpux) && !defined (__hpux)
  5938. Xextern  int getopt (int, char **, char *);
  5939. X# endif
  5940. X
  5941. Xint      main (int, char **);
  5942. Xint     server_response (int);
  5943. Xint      build_tcp_connection (char *, int);
  5944. Xint     sighandle (int);
  5945. Xint     urg_data (int);
  5946. Xint     alarm_clock (int);
  5947. Xlong int read_from_fd (int, long int, FILE *);
  5948. Xlong int write_to_fd (int, char *, long int);
  5949. Xint     open_file (char *, int, int);
  5950. Xint      check_server_response (int, char *);
  5951. Xint     check_for_redirection (char *, char *);
  5952. XFILE     *check_for_pipe (char *);
  5953. Xint     prevch (char *, char *);
  5954. Xint     nextch (char *);
  5955. X
  5956. Xlong int nbytes, sock_fd, buffsiz = BUFFSIZ;
  5957. Xint  to_file, prompt_len, verbose, check_sio, response_timeout = TIMEOUT,
  5958. X  fd = -1, broken_pipe = 0, sigint = 1, interrupted = 0, cmd, no_abort_op = 0,
  5959. X  pliteral, nliteral, literal, timed_out;
  5960. X
  5961. Xchar args [256];
  5962. XFILE *pipefp = NULL;
  5963. X#endif
  5964. X
  5965. X/*
  5966. X  Main function. Connect to server, issue requests and receive replies.
  5967. X
  5968. X  Returns: 0 on success, 1 on command line option error, or an ILPP
  5969. X       command if the transaction was terminated normally.
  5970. X*/
  5971. X
  5972. Xmain (int argc, char **argv)
  5973. X{
  5974. X#ifndef GO_INTERACTIVE
  5975. X  printf ("%s not functional. Try compiling archives/ilp/ilp.c\n", argv[0]);
  5976. X#else
  5977. X  char *options = "vt:b:";
  5978. X  char *buf, *tmp, infile [256], wbuf [256], version [80];
  5979. X  int i, port, timeout, sprompt_len, c, rfd, bytes_alloced = 0, rtc = TIMEOUT;
  5980. X  struct stat stat_buf;
  5981. X  extern char *optarg;
  5982. X  port = PORT;
  5983. X  while ((c = getopt (argc, argv, options)) != EOF)
  5984. X    switch ((char) c) {
  5985. X    case 'v': verbose = 1; break;
  5986. X    case 't':
  5987. X      if ((response_timeout = atoi (optarg)) < 1) {
  5988. X    printf ("-t %d\nBe real.\n", response_timeout);
  5989. X    return 1;
  5990. X      }
  5991. X      rtc = response_timeout;
  5992. X      break;
  5993. X    case 'b':
  5994. X      if ((buffsiz = atol (optarg) * 1024) < 1024) {
  5995. X    printf ("-b %ld\nBe real.\n", buffsiz);
  5996. X    return 1;
  5997. X      }
  5998. X      break;
  5999. X    case '?':
  6000. X    default:
  6001. X      fprintf (stderr, "Usage: %s [-v] [-t timeout] [-b buffer-size in K] \
  6002. X<host> [port]\n", argv[0]);
  6003. X      return 1;
  6004. X    }
  6005. X
  6006. X  if (optind == argc) {
  6007. X    fprintf (stderr, "Usage: %s [-v] [-t timeout] [-b buffer-size in K] \
  6008. X<host> [port]\n", argv[0]);
  6009. X    return 1;
  6010. X  }
  6011. X  else if (optind + 1 < argc)
  6012. X    port = atoi (argv [optind + 1]);
  6013. X# ifdef SIGIO
  6014. X  signal (SIGIO, (void (*)()) urg_data);
  6015. X# endif
  6016. X# ifdef SIGURG
  6017. X  signal (SIGURG, (void (*)()) urg_data);
  6018. X# endif
  6019. X  if ((sock_fd = build_tcp_connection (argv[optind], port)) < 0)
  6020. X    return SYS_ERROR;
  6021. X  if ((cmd = server_response (sock_fd)) != CONNECT) {
  6022. X    PRINTF (cmd, "Handshake failed\n");
  6023. X    printf ("Not an interactive ListProcessor.\n");
  6024. X    return cmd;
  6025. X  }
  6026. X
  6027. X  for (i = SIGHUP; i <= SIGPIPE; i++)
  6028. X    signal (i, (void (*)()) sighandle);
  6029. X  signal (SIGALRM, (void (*)()) alarm_clock);
  6030. X
  6031. X  if (check_server_response (cmd, args)) goto abort;
  6032. X  timeout = nbytes;
  6033. X  sscanf (args, "%s %d %d\n", version, &prompt_len, &sprompt_len);
  6034. X
  6035. X  if ((cmd = server_response (sock_fd)) < 0) goto abort; /* Get greeting */
  6036. X  check_server_response (cmd, args);
  6037. X  if (cmd != CONN_CLOSED && cmd != SERVER_BUSY && cmd != PEER_UNAVAIL &&
  6038. X      cmd != CONN_ABORTED && cmd != SYS_ERROR && cmd != CONN_TIMEOUT)
  6039. X    printf ("\nHit ^\\ (control-backslash) to abort at any time.\n");
  6040. X  if (!strcmp (version, "6.0"))
  6041. X    no_abort_op = 1,
  6042. X    printf ("WARNING: Server does not support the ^C abort operation.\n\
  6043. XWARNING: Server uses another protocol for the append operation >>\n");
  6044. X  if (read_from_fd (sock_fd, nbytes, NULL) < 0) goto abort;
  6045. X  if (cmd == CONN_CLOSED || cmd == SERVER_BUSY || cmd == PEER_UNAVAIL ||
  6046. X      cmd == CONN_ABORTED || cmd == SYS_ERROR || cmd == CONN_TIMEOUT)
  6047. X    goto abort;
  6048. X  bytes_alloced = 256;
  6049. X  if ((buf = (char *) malloc (bytes_alloced * sizeof (char))) == NULL) {
  6050. X    printf ("FATAL: malloc() failed\n");
  6051. X    goto abort;
  6052. X  }
  6053. X  check_sio = 1;
  6054. X  fgets (buf, bytes_alloced - 1, stdin);        /* Put email address */
  6055. X  if (strlen (buf) == 0)
  6056. X    printf ("\n"),
  6057. X    strcpy (buf, "\n");
  6058. X  check_sio = 0;
  6059. X  if (write_to_fd (sock_fd, buf, strlen (buf)) < 0) goto abort;
  6060. X  if ((cmd = server_response (sock_fd)) < 0) /* See if "Password: " follows */
  6061. X    goto abort;
  6062. X  if (check_server_response (cmd, args)) goto abort;
  6063. X  if (cmd == PASSWORD_REQUIRED) {
  6064. X    RESET (buf);
  6065. X    check_sio = 1;
  6066. X    fgets (buf, 255, stdin);
  6067. X    if (strlen (buf) == 0)
  6068. X      printf ("\n"),
  6069. X      strcpy (buf, "\n");
  6070. X    check_sio = 0;
  6071. X    if (write_to_fd (sock_fd, buf, strlen (buf)) < 0)
  6072. X      goto abort;
  6073. X  }
  6074. X  if (cmd == PEER_UNAVAIL) {
  6075. X    read_from_fd (sock_fd, nbytes, NULL);
  6076. X    goto abort;
  6077. X  }
  6078. X
  6079. X  memset (buf, EOS, bytes_alloced);
  6080. X  sigint = 0;
  6081. X  while (cmd != CONN_CLOSED && cmd != CONN_ABORTED && cmd != CONN_TIMEOUT) {
  6082. X    signal (SIGINT, (void (*)()) sighandle);
  6083. X    interrupted = 0;
  6084. X    if ((cmd = server_response (sock_fd)) < 0) break;
  6085. X    if (check_server_response (cmd, args)) break;
  6086. X    if (cmd == TEST_FILE_PERMISSIONS) continue;
  6087. X    interrupted = 0;
  6088. X    if (cmd != CONN_ABORTED && cmd != CONN_TIMEOUT)
  6089. X      if (read_from_fd (sock_fd, nbytes, (cmd != MESSAGE ? pipefp : NULL)) < 0)
  6090. X    break;
  6091. X    signal (SIGINT, SIG_IGN);
  6092. X    broken_pipe = 0;
  6093. X    if (cmd == MESSAGE) {
  6094. X      response_timeout -= 10;
  6095. X      if (response_timeout <= 0)
  6096. X    response_timeout = 1;
  6097. X      continue;
  6098. X    }
  6099. X    if (cmd != CONN_CLOSED && cmd != CONN_ABORTED && cmd != CONN_TIMEOUT) {
  6100. X      response_timeout = rtc;
  6101. X      check_sio = 1;
  6102. X      if (pipefp)
  6103. X    strcpy (buf, "\n");
  6104. X      if (buf [0] == EOS) {
  6105. X        RESET (infile);
  6106. X        if (!fgets (buf, bytes_alloced - 1, stdin))
  6107. X      strcpy (buf, "exit\n");
  6108. X        if (strlen (buf) == 0)    /* EOF */
  6109. X      printf ("\n"),
  6110. X      strcpy (buf, "\n");
  6111. X        if ((rfd = check_for_redirection (buf, infile)) < 0)
  6112. X      strcpy (buf, "\n");
  6113. X        if (rfd >= 0 && infile [0] != EOS) { /* Input redirection */
  6114. X      fstat (rfd, &stat_buf);
  6115. X      if (!(stat_buf.st_mode & S_IFREG)) {
  6116. X        printf ("%s: Not a regular file\n", infile);
  6117. X        strcpy (buf, "\n");
  6118. X        goto skip;
  6119. X      }
  6120. X      if (stat_buf.st_size + strlen (buf) + 2 > bytes_alloced) {
  6121. X        bytes_alloced = stat_buf.st_size + strlen (buf) + 2;
  6122. X        if ((buf = (char *) realloc (buf, bytes_alloced * sizeof (char))) ==
  6123. X            NULL) {
  6124. X          printf ("FATAL: realloc() failed\n");
  6125. X          break;
  6126. X        }
  6127. X      }
  6128. X      i = strlen (buf);
  6129. X      if (read (rfd, &buf [strlen (buf)], stat_buf.st_size) <
  6130. X          stat_buf.st_size) {
  6131. X        printf ("FATAL: Failed to read all of the input file\n");
  6132. X        break;
  6133. X      }
  6134. X      buf [i + stat_buf.st_size] = EOS;
  6135. X      if (buf [i + stat_buf.st_size - 1] != '\n')
  6136. X        strcat (&buf [i + stat_buf.st_size], "\n");
  6137. X      close (rfd);
  6138. X        }
  6139. X      }
  6140. X      skip:
  6141. X      strncpy (wbuf, buf, 254);
  6142. X      tmp = strchr (wbuf, '\n');
  6143. X      if (!tmp)
  6144. X    wbuf [254] = '\n',
  6145. X    wbuf [255] = EOS;
  6146. X      else
  6147. X    *(tmp + 1) = EOS;
  6148. X      if (pipefp)
  6149. X    pclose (pipefp);
  6150. X      check_sio = 0;
  6151. X      pipefp = check_for_pipe (wbuf);
  6152. X      if (write_to_fd (sock_fd, wbuf, strlen (wbuf)) < 0) break;
  6153. X      sprintf (buf, "%s", strchr (buf, '\n') + 1);
  6154. X    }
  6155. X  }
  6156. X
  6157. X  abort:
  6158. X  if (pipefp)
  6159. X    pclose (pipefp);
  6160. X  close (sock_fd);
  6161. X  printf ("Connection closed.\n");
  6162. X  if (buf)
  6163. X    free ((char *) buf);
  6164. X  if (cmd == CONN_CLOSED) 
  6165. X    return 0;
  6166. X  return cmd;
  6167. X#endif
  6168. X}
  6169. X
  6170. X#ifdef GO_INTERACTIVE
  6171. X/*
  6172. X  Get server response. Store in 'nbytes' the number of bytes in the actual
  6173. X  message that follows, and in 'args' the (optional) file name.
  6174. X
  6175. X  Returns: the server reply code, CONN_TIMEOUT, CONN_ABORTED, or -1 on 
  6176. X  protocol errors.
  6177. X*/
  6178. X
  6179. Xint server_response (int sock_fd)
  6180. X{
  6181. X  char buf [256];
  6182. X  int cmd = -1, i, bytes_to_read = 4, bytes_read = 0, value, nfds;
  6183. X  fd_set rfds;
  6184. X  struct timeval timeout;
  6185. X
  6186. X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
  6187. X  defined (apollo) || defined (unknown_port)
  6188. X  nfds = getdtablesize ();
  6189. X# else
  6190. X  nfds = ulimit (UL_GDESLIM);
  6191. X# endif
  6192. X  memset (buf, EOS, 256);
  6193. X  while (bytes_to_read) {
  6194. X    /* Get server command */
  6195. X    FD_ZERO (&rfds);
  6196. X    do {
  6197. X      FD_SET (sock_fd, &rfds);
  6198. X      timeout.tv_sec  = timeout.tv_usec = response_timeout;
  6199. X      errno = 0;
  6200. X      value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
  6201. X    } while (value == -1 && errno == EINTR);
  6202. X
  6203. X    if (value == 0) {
  6204. X      nbytes = 0;
  6205. X      printf ("Server response timeout.\n");
  6206. X      return CONN_TIMEOUT;
  6207. X    }
  6208. X    else if (value < 0) {
  6209. X      perror ("select() failed");
  6210. X      return -1;
  6211. X    }
  6212. X
  6213. X    errno = 0;
  6214. X    /* Get server command */
  6215. X    bytes_read = read (sock_fd, &buf [4 - bytes_to_read], bytes_to_read);
  6216. X    if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
  6217. X    errno == ECONNREFUSED) {
  6218. X      nbytes = 0;
  6219. X      return CONN_ABORTED;
  6220. X    }
  6221. X    if (bytes_read > 0)
  6222. X      bytes_to_read -= bytes_read;
  6223. X  }
  6224. X  buf[3] = EOS;
  6225. X  cmd = atoi (buf);
  6226. X  i = 0;
  6227. X  do {        /* Get # of bytes in actual message */
  6228. X    again1:
  6229. X    FD_ZERO (&rfds);
  6230. X    do {
  6231. X      FD_SET (sock_fd, &rfds);
  6232. X      timeout.tv_sec = timeout.tv_usec = response_timeout;
  6233. X      errno = 0;
  6234. X      value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
  6235. X    } while (value == -1 && errno == EINTR);
  6236. X
  6237. X    if (value == 0) {
  6238. X      nbytes = 0;
  6239. X      printf ("Server response timeout.\n");
  6240. X      return CONN_TIMEOUT;
  6241. X    }
  6242. X    else if (value < 0) {
  6243. X      perror ("select() failed");
  6244. X      return -1;
  6245. X    }
  6246. X
  6247. X    errno = 0;
  6248. X    if (read (sock_fd, &buf[i], 1) < 1) {
  6249. X      if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
  6250. X      errno == ECONNREFUSED) {
  6251. X    nbytes = 0;
  6252. X    return CONN_ABORTED;
  6253. X      }
  6254. X      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
  6255. X    goto again1;
  6256. X      perror ("Protocol error in control string");
  6257. X      return -1;
  6258. X    }
  6259. X    i++;
  6260. X  } while (buf[i - 1] != ' ');
  6261. X
  6262. X  buf[i - 1] = EOS;
  6263. X  nbytes = atoi (buf);
  6264. X  RESET (args);
  6265. X  i = 0;
  6266. X  do {        /* Get filename (optional) */
  6267. X    again2:
  6268. X    FD_ZERO (&rfds);
  6269. X    do {
  6270. X      FD_SET (sock_fd, &rfds);
  6271. X      timeout.tv_sec = timeout.tv_usec = response_timeout;
  6272. X      errno = 0;
  6273. X      value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
  6274. X    } while (value == -1 && errno == EINTR);
  6275. X
  6276. X    if (value == 0) {
  6277. X      nbytes = 0;
  6278. X      printf ("Server response timeout.\n");
  6279. X      return CONN_TIMEOUT;
  6280. X    }
  6281. X    else if (value < 0) {
  6282. X      perror ("select() failed");
  6283. X      return -1;
  6284. X    }
  6285. X
  6286. X    errno = 0;
  6287. X    if (read (sock_fd, &args[i], 1) < 1) {
  6288. X      if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
  6289. X          errno == ECONNREFUSED)
  6290. X        return CONN_ABORTED;
  6291. X      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
  6292. X        goto again2;
  6293. X      perror ("Protocol error in control string");
  6294. X      return -1;
  6295. X    }
  6296. X    ++i;
  6297. X  } while (args[i - 1] != '\n');
  6298. X  args[i - 1]= EOS;
  6299. X  return cmd;
  6300. X}
  6301. X
  6302. X/*
  6303. X  Establish connection with listprocessor. The socket is marked as
  6304. X  non-blocking.
  6305. X
  6306. X  Returns: the socket file descriptor, or -1 on error.
  6307. X*/
  6308. X
  6309. Xint build_tcp_connection (char *host, int port)
  6310. X{
  6311. X  int sock_fd, sendbuf = buffsiz, recvbuf = buffsiz, value = 1, nfds, naddr = 0;
  6312. X  struct sockaddr_in sin;
  6313. X  struct hostent *hostentry;
  6314. X  struct timeval timeout;
  6315. X  fd_set readfds, writefds;
  6316. X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
  6317. X  defined (apollo) || defined (unknown_port)
  6318. X  nfds = getdtablesize ();
  6319. X# else
  6320. X  nfds = ulimit (UL_GDESLIM);
  6321. X# endif
  6322. X  timeout.tv_sec = timeout.tv_usec = 0;
  6323. X  if (!(hostentry = gethostbyname (host))) { /* Host name failed; try IP */
  6324. X    sin.sin_addr.s_addr = inet_addr (host);
  6325. X    if (! (hostentry = gethostbyaddr ((char *) &sin.sin_addr,
  6326. X                      sizeof (struct in_addr),
  6327. X                      AF_INET))) {
  6328. X      printf ("%s: No such host.\n", host);
  6329. X      return -1;
  6330. X    }
  6331. X  }
  6332. X
  6333. X  do {    /* Check all addresses */
  6334. X    if ((sock_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  6335. X      perror ("Could not create socket");
  6336. X      return -1;
  6337. X    }
  6338. X    if (setsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, (char *) &sendbuf,
  6339. X            sizeof (sendbuf)) < 0)
  6340. X      perror ("WARNING: Could not set send-buffer size: setsockopt() error");
  6341. X    if (setsockopt (sock_fd, SOL_SOCKET, SO_RCVBUF, (char *) &recvbuf,
  6342. X            sizeof (recvbuf)) < 0)
  6343. X      perror ("WARNING: Could not set receive-buffer size: setsockopt() error");
  6344. X    if (setsockopt (sock_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &value,
  6345. X            sizeof (value)) < 0)
  6346. X      perror ("WARNING: Cannot toggle keep-alive connections: setsockopt() error");
  6347. X
  6348. X# ifdef h_addr
  6349. X    memcpy ((char *) &sin.sin_addr.s_addr,
  6350. X        (char *) hostentry->h_addr_list[naddr++],
  6351. X        hostentry->h_length);
  6352. X# else
  6353. X    memcpy ((char *) &sin.sin_addr.s_addr,
  6354. X        (char *) hostentry->h_addr,
  6355. X        hostentry->h_length);
  6356. X# endif
  6357. X    sin.sin_family = AF_INET;
  6358. X    sin.sin_port = htons (port);
  6359. X    memset (sin.sin_zero, EOS, sizeof (sin.sin_zero));
  6360. X    printf ("Trying %s ... ", inet_ntoa (sin.sin_addr));
  6361. X    fflush (stdout);
  6362. X    if (connect (sock_fd, (struct sockaddr *) &sin, 
  6363. X         sizeof (struct sockaddr_in)) < 0) {
  6364. X      if (errno != EINPROGRESS) {
  6365. X# ifdef h_addr
  6366. X    if (!hostentry->h_addr_list[naddr]) {
  6367. X# endif    
  6368. X      perror ("");
  6369. X      close (sock_fd);
  6370. X      return -1;
  6371. X# ifdef h_addr
  6372. X    }
  6373. X    else {
  6374. X      perror ("");
  6375. X      close (sock_fd);
  6376. X      continue;
  6377. X    }
  6378. X# endif
  6379. X      }
  6380. X      FD_ZERO (&readfds);
  6381. X      FD_ZERO (&writefds);
  6382. X      do {
  6383. X    FD_SET (sock_fd, &readfds);
  6384. X    FD_SET (sock_fd, &writefds);
  6385. X    errno = 0;
  6386. X    value = select ((nfds > 0 ? nfds : 20), &readfds, &writefds, NULL,
  6387. X            &timeout);
  6388. X      } while (value == -1 && errno == EINTR);
  6389. X
  6390. X      if (value < 0) {
  6391. X    perror ("select() error");
  6392. X    close (sock_fd);
  6393. X    return -1;
  6394. X      }
  6395. X      break;    /* Successful connection */
  6396. X    }
  6397. X    else
  6398. X      break;
  6399. X  } while (007);
  6400. X  printf ("\n");
  6401. X# ifdef NONBLOCKING_IO
  6402. X  if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | O_NDELAY)) < 0) {
  6403. X    perror ("Could not set non-blocking I/O");
  6404. X    close (sock_fd);
  6405. X    return -1;
  6406. X  }
  6407. X# endif
  6408. X# if defined (sco) || defined (M_XENIX) || defined (M_UNIX)
  6409. X  if (ioctl (sock_fd, I_SETSIG, S_INPUT) < 0) {
  6410. X    perror ("Cannot set SIGIO");
  6411. X    close (sock_fd);
  6412. X    return -1;
  6413. X  }
  6414. X# else
  6415. X#  ifdef F_SETOWN
  6416. X  if (fcntl (sock_fd, F_SETOWN, getpid()) < 0) {
  6417. X    perror ("Cannot assign socket to process group");
  6418. X    close (sock_fd);
  6419. X    return -1;
  6420. X  }
  6421. X#  elif defined (SIOCSPGRP)
  6422. X  value = -getpid();
  6423. X  if (ioctl (sock_fd, SIOCSPGRP, (char *) &value) < 0) {
  6424. X    perror ("Cannot assign socket to process group");
  6425. X    close (sock_fd);
  6426. X    return -1;
  6427. X  }
  6428. X#  else
  6429. X  perror ("Cannot assign socket to process group");
  6430. X  close (sock_fd);
  6431. X  return -1;
  6432. X#  endif
  6433. X#  ifdef FASYNC
  6434. X  if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | FASYNC)) < 0) {
  6435. X    perror ("Cannot set asynchronous I/O for socket");
  6436. X    close (sock_fd);
  6437. X    return -1;
  6438. X  }
  6439. X#  elif defined (FIOASYNC)
  6440. X  value = 1;
  6441. X  if (ioctl (sock_fd, FIOASYNC, (char *) &value) < 0) {
  6442. X    perror ("Cannot set asynchronous I/O for socket");
  6443. X    close (sock_fd);
  6444. X    return -1;
  6445. X  }
  6446. X#  else
  6447. X  perror ("Cannot set asynchronous I/O for socket");
  6448. X  close (sock_fd);
  6449. X  return -1;
  6450. X#  endif
  6451. X# endif
  6452. X  return sock_fd;
  6453. X}
  6454. X
  6455. X/*
  6456. X  Handle signals; the client sends an '__abort__' command and exits, if sig
  6457. X  is SIGQUIT; '__abort__' causes the other end to shut down. On SIGINT, it
  6458. X  sends an abort operation and waits for the server's reply.
  6459. X*/
  6460. X
  6461. Xint sighandle (int sig)
  6462. X{
  6463. X  char ch = EOS, buf [MSGLEN + 1], waste [BUFSIZ];
  6464. X  int atoobmark, val, val2, once = 0, nfds;
  6465. X  long int discarded_bytes = 0;
  6466. X  fd_set readfds;
  6467. X  struct timeval timeout;
  6468. X  if (sig == SIGHUP) {
  6469. X    signal (sig, (void (*)()) sighandle);
  6470. X    return 0;
  6471. X  }
  6472. X  else if (sig == SIGPIPE) {
  6473. X    if (!broken_pipe)
  6474. X      printf ("Broken pipe\n");
  6475. X    broken_pipe = 1;
  6476. X    signal (sig, (void (*)()) sighandle);
  6477. X    return 0;
  6478. X  }
  6479. X  else if (sig == SIGINT)
  6480. X    if (!sigint) {
  6481. X      if (no_abort_op) {
  6482. X    signal (sig, (void (*)()) sighandle);
  6483. X    return 0;
  6484. X      }
  6485. X# ifndef NO_ABORT_OP
  6486. X      signal (sig, SIG_IGN);
  6487. X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
  6488. X  defined (apollo) || defined (unknown_port)
  6489. X      nfds = getdtablesize ();
  6490. X# else
  6491. X      nfds = ulimit (UL_GDESLIM);
  6492. X# endif
  6493. X      do {    /* Send abort op char as OOB data */
  6494. X    errno = 0;
  6495. X    val = send (sock_fd, "\03", 1, MSG_OOB);
  6496. X      } while (val == -1 &&
  6497. X           (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR));
  6498. X      if (val < 0)
  6499. X    perror ("send()");
  6500. X      else {
  6501. X    timeout.tv_sec = timeout.tv_usec = 0;
  6502. X    /* Look for the OOB mark; discard data before it; read the OOB byte
  6503. X       and message when at mark */
  6504. X    for (;;) {
  6505. X      FD_ZERO (&readfds);
  6506. X      do {
  6507. X        FD_SET (sock_fd, &readfds);
  6508. X        errno = 0;
  6509. X        if (once)
  6510. X          timeout.tv_sec = timeout.tv_usec = 3;
  6511. X        val = select ((nfds > 0 ? nfds : 20), &readfds, NULL, NULL,
  6512. X              &timeout);
  6513. X        if (val == 0 && once) {    /* Reached end of socket */
  6514. X          write_to_fd (sock_fd, "\n",1); /* NOOP; resend prompt */
  6515. X          goto _abort;
  6516. X        }
  6517. X      } while (val == -1 && errno == EINTR);
  6518. X
  6519. X      if (val < 0) {
  6520. X        perror ("select() error");
  6521. X        break;
  6522. X      }
  6523. X
  6524. X      if (ioctl (sock_fd, SIOCATMARK, &atoobmark) < 0) {
  6525. X        perror ("FATAL: ioctl()");    /* OS bug if this happens */
  6526. X        break;
  6527. X      }
  6528. X      if (atoobmark) {    /* Ready to get message */
  6529. X        int bytes_to_read = MSGLEN, bytes_read = 0, val;
  6530. X        do {    /* Get OOB byte */
  6531. X          val = recv (sock_fd, &ch, 1, MSG_OOB);
  6532. X          if (val < 0 && errno && errno != EWOULDBLOCK && errno != EAGAIN
  6533. X          && errno != EINTR && errno != EINVAL) {
  6534. X        perror ("recv()");    /* OS bug if this happens */
  6535. X        break;
  6536. X          }
  6537. X        } while (val == -1 || ch != '#');
  6538. X        while (bytes_to_read) { /* Read message. i.e. bytes sent */
  6539. X          val = recv (sock_fd, &buf[bytes_read], bytes_to_read, NULL);
  6540. X          if (val > 0)
  6541. X        bytes_read += val,
  6542. X        bytes_to_read = MSGLEN - bytes_read;
  6543. X        }
  6544. X        buf [MSGLEN] = EOS;
  6545. X        fprintf (stderr, "Aborted after transferring %ld bytes.\n", 
  6546. X             ((val = atoi (buf) - discarded_bytes) > 0 ? val : 
  6547. X              atoi (buf)));
  6548. X        /* Now prompt follows */
  6549. X        break;
  6550. X      }
  6551. X      errno = 0;
  6552. X      /* Read and discard data until OOB mark */
  6553. X      val = read (sock_fd, waste, sizeof (waste));
  6554. X      if (val < 0 && errno != EWOULDBLOCK && errno != EAGAIN &&
  6555. X          errno != EINTR) {
  6556. X        if (errno == 0) {    /* Reached end of socket */
  6557. X          write_to_fd (sock_fd, "\n", 1);    /* NOOP; resend prompt */
  6558. X          goto _abort;
  6559. X        }
  6560. X        else
  6561. X          perror ("read()");
  6562. X        exit (1);
  6563. X      }
  6564. X      if (val > 0) {
  6565. X        discarded_bytes += val;
  6566. X        /* Also send 0x3 once in the regular way just in case the server
  6567. X           finished sending before receiving our abort request */
  6568. X        if (!once) {
  6569. X          once = 1;
  6570. X          write_to_fd (sock_fd, "\03", 1);
  6571. X        }
  6572. X      }
  6573. X    }
  6574. X      }
  6575. X# endif
  6576. X     _abort:
  6577. X      interrupted = 1;
  6578. X      cmd = MESSAGE;
  6579. X      signal (sig, (void (*)()) sighandle);
  6580. X      return 0;
  6581. X    }
  6582. X  check_sio = 0;
  6583. X  write_to_fd (sock_fd, "__abort__\n", 10);
  6584. X  close (sock_fd);
  6585. X  if (pipefp)
  6586. X    pclose (pipefp);
  6587. X  printf ("Connection closed.\n");
  6588. X  exit (sig);
  6589. X}
  6590. X
  6591. X/*
  6592. X  Urgent data from server; read it and exit. Urgent data is received
  6593. X  when a connection is timed out or when the server shuts down.
  6594. X*/
  6595. X
  6596. Xint urg_data (int sig)
  6597. X{
  6598. X  int cmd;
  6599. X
  6600. X  if (!check_sio) {
  6601. X    signal (sig, (void (*)()) urg_data);
  6602. X    return 0;
  6603. X  }
  6604. X  signal (sig, SIG_IGN);
  6605. X  if ((cmd = server_response (sock_fd)) >= 0)
  6606. X    if (cmd == CONN_ABORTED || cmd == CONN_TIMEOUT || cmd == CONN_CLOSED)
  6607. X      check_server_response (cmd, args),
  6608. X      read_from_fd (sock_fd, nbytes, NULL);
  6609. X  shutdown (sock_fd, 2);
  6610. X  kill (0, SIGHUP);
  6611. X  if (pipefp)
  6612. X    pclose (pipefp);
  6613. X  printf ("Connection closed.\n");
  6614. X  exit (cmd);
  6615. X}
  6616. X
  6617. X/*
  6618. X  Alarm signals a server timeout.
  6619. X*/
  6620. X
  6621. Xint alarm_clock (int sig)
  6622. X{
  6623. X  timed_out = 1;
  6624. X  signal (sig, (void (*)()) alarm_clock);
  6625. X}
  6626. X
  6627. X/*
  6628. X  Read from a socket and either echo to tty or save to a file.
  6629. X
  6630. X  Returns: the actual number of bytes read on succes, or the negative of
  6631. X  that number (or -1) on error.
  6632. X*/
  6633. X
  6634. Xlong int read_from_fd (int rfd, long int bytes_to_read, FILE *pipefp)
  6635. X{
  6636. X  long int bytes_read = 0, total_bytes = 0;
  6637. X  int to_pipe = 1;
  6638. X  char *buf;
  6639. X
  6640. X  timed_out = 0;
  6641. X  signal (SIGALRM, (void (*)()) alarm_clock);
  6642. X  alarm (response_timeout);
  6643. X  if (bytes_to_read <= 0)
  6644. X    return 0;
  6645. X  if ((buf = (char *) malloc (buffsiz * sizeof (char))) == NULL) {
  6646. X    printf ("malloc() failed while attempting to allocate %ld bytes\n",
  6647. X         buffsiz);
  6648. X    return -1;
  6649. X  }
  6650. X  errno = 0;
  6651. X  while (!interrupted && 
  6652. X     (bytes_read = read (rfd, buf, MIN (bytes_to_read, buffsiz))) <
  6653. X     bytes_to_read) {
  6654. X    if (bytes_read < 0 && errno && errno != EWOULDBLOCK &&
  6655. X    errno != EAGAIN && errno != EINTR
  6656. X# ifdef ERESTART
  6657. X    && errno != ERESTART
  6658. X# endif
  6659. X    ) {
  6660. X      char error [256];
  6661. X      switch (errno) {
  6662. X      case EBADF: sprintf (error, "Bad file number"); break;
  6663. X      case EFAULT: sprintf (error, "Bad address"); break;
  6664. X      case EFBIG: sprintf (error, "File limit reached"); break;
  6665. X      case EINVAL: sprintf (error, "Negative seek pointer"); break;
  6666. X      case EIO: sprintf (error, "I/O error"); break;
  6667. X      case ENOSPC: sprintf (error, "No space left on device"); break;
  6668. X      case ENXIO: sprintf (error, "No such device or address"); break;
  6669. X      case ERANGE: sprintf (error, "Bytes to read (%ld) out of \
  6670. Xrange", bytes_to_read); break;
  6671. X# ifdef ENETRESET
  6672. X      case ENETRESET: sprintf (error, "Network dropped connection"); break;
  6673. X# endif
  6674. X      default: sprintf (error, "Error number %d", errno);
  6675. X      }
  6676. X      fprintf (stderr, "%s\n", error);
  6677. X      free ((char *) buf);
  6678. X      return -1;
  6679. X    }
  6680. X    else if (!pipefp && timed_out) {
  6681. X      printf ("Server response timeout.\n");
  6682. X      free ((char *) buf);
  6683. X      return (total_bytes > 0 ? -total_bytes : -1);
  6684. X    }
  6685. X    if (!interrupted && bytes_read > 0) {
  6686. X      total_bytes += bytes_read;
  6687. X      bytes_to_read -= bytes_read;
  6688. X      if (to_file) {
  6689. X    if (bytes_to_read < prompt_len)
  6690. X      write_to_fd (fileno (stdout),
  6691. X               &buf[bytes_read - prompt_len + bytes_to_read],
  6692. X               prompt_len - bytes_to_read),
  6693. X      to_file = 0;
  6694. X    if (write_to_fd (fd, buf,
  6695. X             (bytes_to_read < prompt_len ? 
  6696. X              bytes_read - prompt_len + bytes_to_read :
  6697. X              bytes_read)) < 0) {
  6698. X      free ((char *) buf);
  6699. X      return (total_bytes > 0 ? -total_bytes : -1);
  6700. X    }
  6701. X      }
  6702. X      else if (pipefp) {
  6703. X    if (to_pipe && !broken_pipe) {
  6704. X      write_to_fd (fileno (pipefp), buf,
  6705. X               (bytes_to_read < prompt_len ? 
  6706. X            bytes_read - prompt_len + bytes_to_read :
  6707. X            bytes_read));
  6708. X      if (errno) {
  6709. X        if (!broken_pipe && errno == EPIPE)
  6710. X          printf ("Broken pipe\n");
  6711. X        broken_pipe = 1;
  6712. X      }
  6713. X    }
  6714. X    if (bytes_to_read < prompt_len)
  6715. X      to_pipe = 0;
  6716. X      }
  6717. X      else
  6718. X    write_to_fd (fileno (stdout), buf, bytes_read);
  6719. X    }
  6720. X    errno = 0;
  6721. X  }
  6722. X  if (!interrupted && bytes_read > 0) {
  6723. X    total_bytes += bytes_read;
  6724. X    if (to_file && bytes_read > prompt_len) {
  6725. X      write_to_fd (fileno (stdout), &buf [bytes_read - prompt_len], prompt_len);
  6726. X      if (write_to_fd (fd, buf, 
  6727. X               (bytes_read > prompt_len ?
  6728. X            bytes_read - prompt_len : bytes_read)) < 0) {
  6729. X    free ((char *) buf);
  6730. X    return (total_bytes > 0 ? -total_bytes : -1);
  6731. X      }
  6732. X    }
  6733. X    else if (pipefp) {
  6734. X      if (!broken_pipe) {
  6735. X    write_to_fd (fileno (pipefp), buf,
  6736. X             (bytes_read > prompt_len ? bytes_read - prompt_len
  6737. X              : 0));
  6738. X    if (errno && !broken_pipe && errno == EPIPE)
  6739. X      printf ("Broken pipe\n");
  6740. X      }
  6741. X    }
  6742. X    else
  6743. X      write_to_fd (fileno (stdout), buf, bytes_read);
  6744. X  }
  6745. X  if (fd >= 0)
  6746. X    close (fd),
  6747. X    fd = -1;
  6748. X  to_file = 0;
  6749. X  free ((char *) buf);
  6750. X  fflush (stdout);
  6751. X  if (pipefp)
  6752. X    fflush (pipefp);
  6753. X  signal (SIGALRM, SIG_IGN);
  6754. X  return total_bytes;
  6755. X}
  6756. X
  6757. X/*
  6758. X  Write to a file descriptor (socket, or regular file).
  6759. X
  6760. X  Returns: the actual number of bytes written on succes, or the negative of
  6761. X  that number (or -1) on error.
  6762. X*/
  6763. X
  6764. Xlong int write_to_fd (int wfd, char *buf, long int bytes_to_write)
  6765. X{
  6766. X  long int bytes_written, total_bytes = 0;
  6767. X
  6768. X  if (bytes_to_write == 0)
  6769. X    return 0;
  6770. X  errno = 0;
  6771. X  while (!interrupted &&
  6772. X     (bytes_written = write (wfd, buf, bytes_to_write)) < bytes_to_write) {
  6773. X    if (bytes_written < 0 && errno && errno != EWOULDBLOCK && errno != EAGAIN
  6774. X    && errno != EINTR
  6775. X# ifdef ERESTART
  6776. X    && errno != ERESTART
  6777. X# endif
  6778. X    ) {
  6779. X      char error [256];
  6780. X      switch (errno) {
  6781. X      case EBADF: sprintf (error, "Bad file number"); break;
  6782. X      case EFAULT: sprintf (error, "Bad address"); break;
  6783. X      case EFBIG: sprintf (error, "File limit reached"); break;
  6784. X      case EINVAL: sprintf (error, "Negative seek pointer"); break;
  6785. X      case EIO: sprintf (error, "I/O error"); break;
  6786. X      case ENOSPC: sprintf (error, "No space left on device"); break;
  6787. X      case ENXIO: sprintf (error, "No such device or address"); break;
  6788. X      case ERANGE: sprintf (error, "Bytes to write (%ld) out of \
  6789. Xrange", bytes_to_write); break;
  6790. X      case EPIPE: sprintf (error, "Server disappeared"); break;
  6791. X# ifdef ENETRESET
  6792. X      case ENETRESET: sprintf (error, "Network dropped connection"); break;
  6793. X# endif
  6794. X      default: sprintf (error, "Error number %d", errno);
  6795. X      }
  6796. X      fprintf (stderr, "%s\n", error);
  6797. X      if (bytes_written > 0)
  6798. X    total_bytes += bytes_written;
  6799. X      return (total_bytes > 0 ? -total_bytes : -1);
  6800. X    }
  6801. X    if (bytes_written > 0)
  6802. X      bytes_to_write -= bytes_written,
  6803. X      total_bytes += bytes_written,
  6804. X      buf += bytes_written;
  6805. X    errno = 0;
  6806. X  }
  6807. X  if (bytes_written > 0)
  6808. X    total_bytes += bytes_written;
  6809. X  return total_bytes;
  6810. X}
  6811. X
  6812. X/*
  6813. X  Open a file for writing or appending. If 'test' is set, make sure
  6814. X  the file is writeable, notify the server and close the file; else prepare
  6815. X  for the transfer. When the server is inquiring about a file's write
  6816. X  permissions it sends zero bytes as the length of the message.
  6817. X
  6818. X  Returns: 0 on succes, -1 otherwise.
  6819. X*/
  6820. X
  6821. Xint open_file (char *file, int mode, int test)
  6822. X{
  6823. X  char msg [4];
  6824. X
  6825. X  if ((fd = open (file, O_CREAT | mode, 0600)) < 0)
  6826. X    to_file = 0,
  6827. X    printf ("%s: Permission denied.\n", args),
  6828. X    nbytes = prompt_len,
  6829. X    sprintf (msg, "%d", PERMISSION_DENIED);
  6830. X  else {
  6831. X    if (nbytes > 0)
  6832. X      to_file = 1,
  6833. X      printf ("Transferring %ld bytes to file %s...\n", nbytes - prompt_len,
  6834. X          file);
  6835. X    else
  6836. X      close (fd),
  6837. X      sprintf (msg, "%d", OK);
  6838. X  }
  6839. X  if (test)
  6840. X    if (write_to_fd (sock_fd, msg, strlen (msg)) < 0)
  6841. X      return -1;
  6842. X  return 0;
  6843. X}
  6844. X
  6845. X/*
  6846. X  Identify the server's response and take appropriate action.
  6847. X
  6848. X  Returns: 0 on success, -1 otherwise.
  6849. X*/
  6850. X
  6851. Xint check_server_response (int cmd, char *file)
  6852. X{
  6853. X    switch (cmd) {
  6854. X    case OK:
  6855. X    case CONNECT:
  6856. X    case SYNTAX_ERROR:
  6857. X    case INVALID_REQ:
  6858. X    case PEER_UNAVAIL:
  6859. X    case BAD_ARCHIVE:
  6860. X    case RESTRICTED_REQ:
  6861. X    case NOT_OWNER:
  6862. X    case SYS_ERROR:
  6863. X    case SERVER_BUSY:
  6864. X    case PASSWORD_REQUIRED:
  6865. X    case PERMISSION_DENIED:
  6866. X    case MESSAGE:
  6867. X    case CONTINUED:
  6868. X    case MORE_INPUT_REQUIRED:
  6869. X    case CONN_ABORTED:
  6870. X    case CONN_TIMEOUT:
  6871. X    case CONN_CLOSED: GENERAL_RESPONSES (cmd); break;
  6872. X    case TEST_FILE_PERMISSIONS: PRINTF (TEST_FILE_PERMISSIONS,
  6873. X     "Testing file permissions\n");
  6874. X     if (open_file (file, O_WRONLY | O_APPEND, 1)) return -1;
  6875. X     break;
  6876. X    case WRITE_TO_FILE_ASC: PRINTF (WRITE_TO_FILE_ASC,
  6877. X     "Writing to file (ASCII)\n");
  6878. X     if (open_file (file, O_WRONLY | O_TRUNC, 0)) return -1;
  6879. X     break;
  6880. X    case WRITE_TO_FILE_BIN: PRINTF (WRITE_TO_FILE_BIN,
  6881. X     "Writing to file (BIN)\n");
  6882. X     if (open_file (file, O_WRONLY | O_TRUNC, 0)) return -1;
  6883. X     break;
  6884. X    case APPEND_TO_FILE_ASC: PRINTF (APPEND_TO_FILE_ASC,
  6885. X     "Appending to file (ASCII)\n");
  6886. X     if (open_file (file, O_WRONLY | O_APPEND, 0)) return -1;
  6887. X     break;
  6888. X    case APPEND_TO_FILE_BIN: PRINTF (APPEND_TO_FILE_BIN,
  6889. X     "Appending to file (BIN)\n");
  6890. X     if (open_file (file, O_WRONLY | O_APPEND, 0)) return -1;
  6891. X     break;
  6892. X    default: printf ("Protocol error: %d\n", cmd); return -1;
  6893. X  }
  6894. X  return 0;
  6895. X}
  6896. X
  6897. X/*
  6898. X  Check for input redirection, and if so check for for permissions too.
  6899. X
  6900. X  Returns: the opened file descriptor on succes, -1 on error.
  6901. X*/
  6902. X
  6903. Xint check_for_redirection (char *buf, char *infile)
  6904. X{
  6905. X  char *r, *s, *b = buf;
  6906. X  int fd = 0, nquote = 0;
  6907. X  extern int literal;
  6908. X
  6909. X  s = buf;
  6910. X  while (*s != EOS) {
  6911. X    prevch (s, b);
  6912. X    if (!nquote) {
  6913. X      if (literal)
  6914. X    *(s - 1) = *s,
  6915. X    *s = (char) 0x1;
  6916. X      else if (*s == '\'')
  6917. X    nquote = 1;
  6918. X      else if (*s == '"')
  6919. X    nquote = 2;
  6920. X      else if (*s == '<') {
  6921. X    if (!literal && infile[0] == EOS) {
  6922. X      RESET (infile);
  6923. X      sscanf (s + 1, "%s", infile);
  6924. X      if (infile [0] == EOS) {
  6925. X        printf ("Invalid null input redirect\n");
  6926. X        return -1;
  6927. X      }
  6928. X      if ((fd = open (infile, O_RDONLY)) < 0) {
  6929. X        printf ("%s: No such file or inadequate permissions\n", infile);
  6930. X        return -1;
  6931. X      }
  6932. X      r = s + 1; /* Remove < and file name */
  6933. X      while (*r != EOS && (*r == ' ' || *r == '\t')) ++r;
  6934. X      while (*r != EOS && !isspace (*r)) ++r;
  6935. X      sprintf (s, "%s", r);
  6936. X      --s;
  6937. X    }
  6938. X      }
  6939. X    }
  6940. X    else if ((nquote == 1 && *s == '\'') ||
  6941. X         (nquote == 2 && *s == '"')) {
  6942. X      if (!literal)
  6943. X    nquote = 0;
  6944. X      else
  6945. X    *(s - 1) = *s,
  6946. X    *s = (char) 0x1;
  6947. X    }
  6948. X    ++s;
  6949. X  }
  6950. X  if (nquote) {
  6951. X    printf ("Mismatched quotes\n");
  6952. X    strcpy (buf, "\n");
  6953. X    if (fd > 0)
  6954. X      close (fd);
  6955. X    return -1;
  6956. X  }
  6957. X  return fd;
  6958. X}
  6959. X
  6960. X/*
  6961. X  Check for  pipe.
  6962. X
  6963. X  Returns: the open file pointer, or NULL.
  6964. X*/
  6965. X
  6966. XFILE *check_for_pipe (char *buf)
  6967. X{
  6968. X  char cmd [1024], *s = buf, *b = buf, nch;
  6969. X  int nquote = 0;
  6970. X  FILE *pipe = NULL;
  6971. X
  6972. X  RESET (cmd);
  6973. X  pliteral = literal = 0;
  6974. X  while (*s != EOS) {
  6975. X    if (*s == (char) 0x1) {
  6976. X      ++s;
  6977. X      continue;
  6978. X    }
  6979. X    nch = nextch (s);
  6980. X    if (!nquote) {
  6981. X      if (*s == '\'' || *s == '"') {
  6982. X    if (nch != (char) 0x1)
  6983. X      nquote = (*s == '\'' ? 1 : 2);
  6984. X      }
  6985. X      else if (*s == '|') {
  6986. X    if (nch != (char) 0x1 && cmd[0] == EOS) {
  6987. X      sscanf (s + 1, "%s", cmd);
  6988. X      if (cmd [0] == EOS) {
  6989. X        printf ("Invalid null pipe\n");
  6990. X        strcpy (buf, "\n");
  6991. X        return NULL;
  6992. X      }
  6993. X      strcpy (cmd, s + 1);
  6994. X      strcpy (s, "\n");
  6995. X      pipe = (FILE *) popen (cmd, "w");
  6996. X    }
  6997. X      }
  6998. X    }
  6999. X    else if ((nquote == 1 && *s == '\'') ||
  7000. X         (nquote == 2 && *s == '"')) {
  7001. X      if (nch != (char) 0x1)
  7002. X    nquote = 0;
  7003. X    }
  7004. X    ++s;
  7005. X  }
  7006. X  for (s = buf; *s != EOS; ++s)
  7007. X    if (*s == 0x1)
  7008. X      *s = *(s - 1),
  7009. X      *(s - 1) = '\\';
  7010. X  if (nquote)
  7011. X    printf ("Mismatched quotes\n"),
  7012. X    strcpy (buf, "\n");
  7013. X  return pipe;
  7014. X}
  7015. X
  7016. X/*
  7017. X  Return the previous character from the current position in the
  7018. X  string. Set 'pliteral' to 1 if that previous character is escaped with \ and
  7019. X  'literal' to 1 if the current character is escaped with \.
  7020. X  In the comments, ^ means "beginning of the string", ? matches any character
  7021. X  except \, * matches absolutely any character and x is the current position.
  7022. X*/
  7023. X
  7024. Xint prevch (char *s, char *b)
  7025. X{
  7026. X  return
  7027. X    ((s) <= (b) ? 
  7028. X     (pliteral = literal = 0, *(s)) : /* ^x */
  7029. X     (((s) - 1) == (b) ? 
  7030. X      (*((s) - 1) == '\\' ? (pliteral = !(literal = 1), *((s) - 1)) /* ^\x */
  7031. X       : (pliteral = literal = 0, *((s) - 1))) /* ^?x */
  7032. X      : (*(s) == '\\' ? 
  7033. X     (*((s) - 2) == '\\' ? (pliteral = !(literal = 0), *((s) - 1)) /* \*\ */
  7034. X      : (*((s) - 1) == '\\' ? (pliteral = !(literal = 1), *((s) - 2)) /* ?\\ */
  7035. X         : (pliteral = literal = 0, *((s) - 1)))) /* ??\ */
  7036. X     : (*((s) - 1) == '\\' ? 
  7037. X        (*((s) - 2) == '\\' ? 
  7038. X         (((s) - 2) == (b) ? (pliteral = !(literal = 0), *((s) - 1)) /* ^\\x */
  7039. X          : (*((s) - 3) == '\\' ? (pliteral = literal = 1,*((s) - 2)) /* \\\x */
  7040. X         : (pliteral = !(literal = 0), *((s) - 1)))) /* ?\\x */
  7041. X         : (((s) - 2) == (b) ? (pliteral = !(literal = 1),*((s) - 2)) /* ^?\x */
  7042. X        : (*((s) - 3) == '\\' ? (pliteral = literal = 1, *((s) - 2)) /* \?\x */
  7043. X           : (pliteral = !(literal = 1),  *((s) - 2))))) /* ??\x */
  7044. X        : (*((s) - 2) == '\\' ? (pliteral = !(literal = 0),*((s) - 1)) /* \?x */
  7045. X           : (pliteral = literal = 0, *((s) - 1))))))); /* ??x */
  7046. X}
  7047. X
  7048. X/*
  7049. X  Return the next character from the current position. The current character
  7050. X  is guarranteed not to be a literal. In the comments below * matches
  7051. X  absolutely any character, ? matches anything but EOS, $ is the EOS and
  7052. X  x marks the current position. Also set 'nliteral' to 1 if the next character
  7053. X  is escaped with \.
  7054. X*/
  7055. X
  7056. Xint nextch (char *s)
  7057. X{
  7058. X  return
  7059. X    (*((s) + 1) == EOS ? (nliteral = 0, EOS) /* x$ */
  7060. X     : (*((s) + 1) == '\\' ? 
  7061. X    (*((s) + 2) == EOS ? (nliteral = 0, *((s) + 1)) /* x\$ */
  7062. X     : (nliteral = 1, *((s) + 2))) /* x\? */
  7063. X    : (nliteral = 0, *((s) + 1)))); /* x* */
  7064. X}
  7065. X#endif
  7066. *-*-END-of-src/ilp.c-*-*
  7067. echo x - src/list.c
  7068. sed 's/^X//' >src/list.c <<'*-*-END-of-src/list.c-*-*'
  7069. X/*
  7070. X  ----------------------------------------------------------------------------
  7071. X  |            MAILING LIST MAIL-DISTRIBUTION PROGRAM             |
  7072. X  |                                         |
  7073. X  |                 Version 5.1                     |
  7074. X  |                                                                          |
  7075. X  |                (or, when Computer Science gets to you)                   |
  7076. X  |                                         |
  7077. X  |               Written by Anastasios Kotsikonas                      |
  7078. X  |                      (tasos@cs.bu.edu)                          |
  7079. X  |                                                                         |
  7080. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  7081. X  | whole and not in parts, as long as you do not remove or alter the author |
  7082. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  7083. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  7084. X  | provided for your personal use, you may not alter the functions         |
  7085. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  7086. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  7087. X  | any changes you may have made. No part of the source code bearing a         |
  7088. X  | copyright notice can be included in commercial software systems without  |
  7089. X  | written permission by the author.                         |
  7090. X  | By using this software you are bound by this agreement.             |
  7091. X  | This software comes with no warranties and cannot be sold for profit.    |
  7092. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  7093. X  | files when distributing this software.                                   |
  7094. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  7095. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  7096. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  7097. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  7098. X  | (ii).                                                                    |
  7099. X  ----------------------------------------------------------------------------
  7100. X
  7101. X  NOTE: Anything appearing in capital letters refers to #define's in the
  7102. X  header files provided.
  7103. X
  7104. X  PURPOSE: Create mailing lists. Members of the list send messages to
  7105. X  them, and each of these messages is forwarded to the rest of the members.
  7106. X  Any message(s) not from subscribers are returned to the original senders,
  7107. X  or can be forwarded to MANAGER. Messages from "undesired" senders can be
  7108. X  ignored by placing their email addresses in the IGNORED file (this would
  7109. X  usually include root and the list's login name to avoid infinite loops).
  7110. X  Distributed may be automatically archived.
  7111. X
  7112. X  OVERVIEW: A mailing list resides in a subdirectory of HOMEDIR/lists
  7113. X  whose name is the list's alias (in the aliases file) in capital letters.
  7114. X  When the program is killed or it abnormally dies, a message
  7115. X  is sent to MANAGER (if using UCB mail) along with a copy of the current 
  7116. X  report file (more on that below). Use the -1 flag when running the
  7117. X  program. The mailing list to be processed is given as argument to the
  7118. X  -L option in upper case. Any progress is reported to the list's REPORT_LIST
  7119. X  file and to the administrator's terminal. All messages sent to this list are
  7120. X  saved in the MBOX file. The program can be run as stand-alone, or in
  7121. X  conjunction with the other programs provided (start, serverd and listproc).
  7122. X  Please note that a line beginning with "From " and another one beginning
  7123. X  with "From: " must appear in the header of each message, and a blank line
  7124. X  must separate the header from the body of the message. Mailing lists
  7125. X  can be linked with peers and have access to news groups. A crash recovery
  7126. X  mechanism is built into the system, so that when the system is aborted
  7127. X  while a delivery is taking place, it will resume delivery from where
  7128. X  it left off.
  7129. X
  7130. X  COMMAND LINE OPTIONS:
  7131. X    -r: Restricted mail; since it is possible to have another distribution
  7132. X        list at some other site as a subscriber, then the following problem
  7133. X    arises: if a message is coming from a member of the other list, his/
  7134. X    her message was forwarded to the members of that list from the other
  7135. X    site; we do not want to send this message back to them, because they
  7136. X    will receive this message twice. Therefore, when this flag is on,
  7137. X    for every message received, its sender is checked against a list
  7138. X    of "restricted" mail addresses (a subset of the subscribers). If a
  7139. X    match is found, then mail is forwarded to the people listed in the
  7140. X    filename following this email address -- for the appropriate format
  7141. X    see below. If no match is found, then the message is forwarded to
  7142. X    to all of the subscribers. See also below.
  7143. X    -1: Execute only once; this is used when the program is running in
  7144. X        conjunction with listproc, in which case execution is interchanged
  7145. X        and controlled by the serverd program.
  7146. X    -e: Echo reports to the screen.
  7147. X    -s: Do not check for subscriptions.
  7148. X    -p: By default, replies to posted (to news) messages go to the list;
  7149. X    this option forces replies to be forwarded to the original author.
  7150. X    -P: By default, replies to distributed messages go to the list; this option
  7151. X    forces replies to be forwarded to the original author.
  7152. X    -m: Usually, each outgoing message has a single recipient. This switches
  7153. X        to multiple recipients -- the argument to it is the number of
  7154. X    multiple recipients to be included in this message.
  7155. X    -v: Display the version number of this package.
  7156. X    -f: Forward any message(s) from unsubscribed senders to the list's
  7157. X        owner. This way, any ordinary user account can be used as the list's
  7158. X        address.
  7159. X    -L: The argument following is the list name to process.
  7160. X    -D: Turn debug on. A transaction of the last email sent out is kept
  7161. X        in the files HOMEDIR/sent and HOMEDIR/received. This assumes
  7162. X        use of the 'system' mail method.
  7163. X    -M: List is moderated.  Incoming messages go to owner unless
  7164. X        they are from owner in which case they get posted.
  7165. X    -d: Send out the digest even though it's not full
  7166. X    -i: Send out a digest to one user (whose name is the argument)
  7167. X    -Z: Turn off automatic compression of archived message.
  7168. X
  7169. X  DISCLAIMER: If for any reason during the use of this program, implied
  7170. X  or not, you happen to die, or suffer any injury of any kind (physical
  7171. X  or mental), I, Mr. Anastasios Kotsikonas, AM NOT RESPONSIBLE at all.
  7172. X  In fact, I AM NOT RESPONSIBLE FOR ANYTHING that may happen to you, or
  7173. X  your computer and operating system.
  7174. X
  7175. X  PLEASE: If you upgrade the code, send me a copy, and do not even attempt to
  7176. X  put your name for credit. Send to tasos@cs.bu.edu or tasos@bucsf.bu.edu.
  7177. X
  7178. X  EXIT CODES:
  7179. X    0: OK
  7180. X    1: Could not open or lock file
  7181. X    2: SIGINT signal
  7182. X    3: Command line option error
  7183. X    4: Syntax error in file
  7184. X    5: Could not spawn
  7185. X    6: Shutdown request
  7186. X    7: Restart request
  7187. X    8: Received system signal
  7188. X    9: Too many multiple recipients
  7189. X   10: Could not deliver mail
  7190. X   11: Malloc failed
  7191. X   12: Cannot fork
  7192. X   13: Socket connection problem
  7193. X   14: Semaphore error
  7194. X   15: Cannot setuid, setgid
  7195. X   16: Internal error
  7196. X
  7197. X  ENJOY!!!
  7198. X
  7199. X  Approximate algorithm:
  7200. X  {
  7201. X    If DIGEST_TMP file exists
  7202. X      send it to digest subscribers
  7203. X
  7204. X    If the -d flag is on
  7205. X      make a digest
  7206. X      send it to digest subscribers
  7207. X
  7208. X    Place a lock so that no other list program will access any files.
  7209. X    Read LIST_MAIL_FILE
  7210. X    If new message(s) have arrived then {
  7211. X      Lock LIST_MAIL_FILE so catmail can't append to it
  7212. X      Append messages to MBOX and truncate LIST_MAIL_FILE
  7213. X      Unlock LIST_MAIL_FILE
  7214. X
  7215. X      For each message do {
  7216. X        If the person is in the IGNORED file, go on to the next message.
  7217. X        If the person sending it is subscribed (listed in SUBSCRIBERS) then
  7218. X      If the person does not acknowledge his/her message, he/she
  7219. X        never receives his/her message back
  7220. X
  7221. X          If the -m flag is on then
  7222. X            If the article comes from someone who is not the owner
  7223. X              forward to the owner
  7224. X              go on to next message
  7225. X            Else
  7226. X              remove headers accumulated in passing to the moderator and back
  7227. X              figure out original sender and subject
  7228. X
  7229. X      If the -r flag is on then
  7230. X        check if the sender is listed in RESTRICTED
  7231. X        If so then
  7232. X          forward mail to all people listed in the file after the 
  7233. X          restricted-sender's address
  7234. X        Else
  7235. X          distribute to all people in SUBSCRIBERS
  7236. X      Else
  7237. X        distribute to all people in SUBSCRIBERS, NEWSF (only to those
  7238. X        newsgroups that are supposed to received messages) and PEERS
  7239. X        according to the following:
  7240. X          Email from regular SUBSCRIBERS is sent to NEWS and PEERS as well
  7241. X          Email from news is sent to SUBSCRIBERS and PEERS
  7242. X          Email from peers is sent to SUBSCRIBERS and NEWS
  7243. X    Else if it news feed (listed in NEWSF)
  7244. X      distribute to SUBSCRIBERS
  7245. X        Else 
  7246. X          if -f specified, forward it to MANAGER; otherwise return the
  7247. X      message to the sender.
  7248. X    Archive message is requested.
  7249. X      }
  7250. X      Remove mail files.
  7251. X    }
  7252. X    Repeat process after IDLE_TIME, or die if -1 specified.
  7253. X  }
  7254. X
  7255. X  Required files:
  7256. X    SUBSCRIBERS     <-- The list of subscribed people
  7257. X    ALIASES        <-- Aliases of email addresses of subscribers, news & peers
  7258. X    NEWSF        <-- List of news groups
  7259. X    PEERS        <-- List of peer lists
  7260. X    RESTRICTED      <-- Addresses of senders whose messages
  7261. X                        require special handling (usually 
  7262. X                addresses of other lists): mail is 
  7263. X            forwarded only to people found in the 
  7264. X            file after the sender's address; see below
  7265. X    IGNORED         <-- The list of undesired people
  7266. X
  7267. X  Input files:
  7268. X    LIST_MAIL_FILE  <-- File where new messages go
  7269. X    MAIL_COPY       <-- Copy of this file (actual work file)
  7270. X    MSG_NO          <-- Current message count
  7271. X    DIGEST_NO       <-- Current digest count
  7272. X    SUBSCRIBERS
  7273. X    RESTRICTED
  7274. X    IGNORED
  7275. X
  7276. X  Output files:
  7277. X    MBOX            <-- A log of all messages sent to date
  7278. X    REPORT_LIST     <-- Progress report
  7279. X    HEADERS        <-- A log of all emails sent (just the sender's address)
  7280. X    MSG             <-- Body of message (no header)
  7281. X    MSG_NO          <-- Write last message count
  7282. X    DIGEST_NO       <-- Write last digest count
  7283. X    MAILFORWARD     <-- Completed message (with header and a copy
  7284. X                of MSG) to be forwarded
  7285. X
  7286. X  Format of the SUBSCRIBERS file:
  7287. X    One entry per line; each entry is the full email address of the subscriber
  7288. X    as it appears in the "From " field, followed by the word "ACK" (in which
  7289. X    case his/her message will be sent back to him/her as an acknowledgement)
  7290. X    "NOACK" (the opposite), POSTPONE (no mail will be sent until the
  7291. X    user changes mode again), or DIGEST (digests are periodically sent),
  7292. X    followed by a string that plays the role of a password, followed by either
  7293. X    YES or NO which play the role of the conceal attribute, followed by the
  7294. X    subscriber's name. Do not include any blank lines.
  7295. X
  7296. X  Format of the RESTRICTED file:
  7297. X    One entry per line; each entry is the full email address of the
  7298. X    subscriber, followed by a file name where email addresses of recipients
  7299. X    are listed (just like in the SUBSCRIBERS file).When mail arrives from a 
  7300. X    sender listed in the RESTRICTED file and the -r flag is on, then mail 
  7301. X    will not be forwarded to SUBSCRIBERS, but instead to the people 
  7302. X    listed in the file following the restricted-sender's address. Example:
  7303. X      tasos@bucsf.bu.edu  /grad/tasos/.recipients
  7304. X      tasos@cs.bu.edu     /grad/tasos/.otherrecipients
  7305. X    If the recipient file given is the word "NONE", then no one will receive
  7306. X    any messages. This is useful in the case that other distribution sites
  7307. X    are subscribers and do forward the message back to the sender, 
  7308. X    in which case we protect ourselves from multiple reception of the same
  7309. X    messages. 
  7310. X    For example, when two (or more) lists are mutual subscribers, and a 
  7311. X    message originated by someone in our list, this message, after being 
  7312. X    distributed locally, is sent to the other list; if the other site does
  7313. X    send messages back to the sender, this message will be forwarded to us
  7314. X    to be distributed again, something which is highly undesirable. 
  7315. X    This precludes that the other site sends messages identified only by
  7316. X    their original senders, something which is unlikely but possible.
  7317. X    In this case, we would put our list as one of the entries in the 
  7318. X    RESTRICTED file, with the word NONE next to it. Do not include 
  7319. X    any blank lines.
  7320. X
  7321. X  Format of the PEERS file:
  7322. X    One entry per line -- the email address of the peer list, followed
  7323. X    by its mail mode (NOACK), followed by the remote alias (how the peer list
  7324. X    is known in the remote host), followed by the email address of the
  7325. X    remote server that handles the remote peer list.
  7326. X
  7327. X  Format of the NEWSF file:
  7328. X    One entry per line -- the email address of the news group, followed
  7329. X    by its mail mode (POSTPONE or NOACK), followed by the news group's name.
  7330. X
  7331. X  Format of the IGNORED file:
  7332. X    One entry per line -- the email addresses of the people whose messages
  7333. X    are to be ignored. This is a good place to put root, sys and other
  7334. X    such undesired logins. See doc/server.nr for information.
  7335. X
  7336. X  Format of the ALIASES file:
  7337. X    One entry per line -- the new alias followed by the email address the
  7338. X    user is subscribed with. See doc/server.nr for information.
  7339. X
  7340. X*/
  7341. X
  7342. X#include <stdio.h>
  7343. X#include <sys/types.h>
  7344. X#ifdef SYSLOG
  7345. X# ifdef ultrix
  7346. X#  include <sys/syslog.h>
  7347. X# else
  7348. X#  include <syslog.h>
  7349. X# endif
  7350. X#endif
  7351. X#include <ctype.h>
  7352. X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
  7353. X  && !defined (sequent) && !defined (unknown_port)
  7354. X# include <malloc.h>
  7355. X#endif
  7356. X#include <string.h>
  7357. X#ifndef unknown_port
  7358. X# ifndef __NeXT__
  7359. X#  include <unistd.h>
  7360. X# else
  7361. X#  include <libc.h>
  7362. X# endif
  7363. X#endif
  7364. X#include <sys/stat.h>
  7365. X#if !defined (sequent) && !defined (__NeXT__) && !defined (__convex__) && \
  7366. X !defined (apollo) && !defined (i386) && !defined (unknown_port)
  7367. X# include <sys/termio.h>
  7368. X#endif
  7369. X#ifndef sun
  7370. X# include <sys/ioctl.h>
  7371. X#endif
  7372. X#include <fcntl.h>
  7373. X#include <signal.h>
  7374. X#include <time.h>
  7375. X#include <errno.h>
  7376. X#ifdef unknown_port
  7377. Xextern int errno;
  7378. X#endif
  7379. X#include "defs.h"
  7380. X#include "list.h"
  7381. X#include "struct.h"
  7382. X#include "global.h"
  7383. X#if defined (__NeXT__) || defined (unknown_port)
  7384. X# include "next.h"
  7385. X#endif
  7386. X
  7387. X#ifdef TCP_IP
  7388. X# include <sys/socket.h>
  7389. X# include <netdb.h>
  7390. X# include <netinet/in.h>
  7391. Xstruct     in_addr localaddr;
  7392. X#else
  7393. Xchar     *localaddr;
  7394. X#endif
  7395. X
  7396. X#ifdef GO_INTERACTIVE
  7397. X# include <sys/ipc.h>
  7398. X# include <sys/sem.h>
  7399. X#endif
  7400. X
  7401. X/* 
  7402. X  Function prototypes:
  7403. X*/
  7404. X
  7405. X#ifdef __STDC__
  7406. X# include <stdarg.h>
  7407. Xextern int  syscom (char *, ...);
  7408. Xextern char *tsprintf (char *, ...);
  7409. X#else
  7410. X# include <varargs.h>
  7411. Xextern int  syscom ();
  7412. Xextern char *tsprintf ();
  7413. X#endif
  7414. X#ifndef __NeXT__
  7415. Xextern long int atoi (char *);
  7416. X#else
  7417. Xextern int atoi (const char *);
  7418. X#endif
  7419. Xextern int  sys_config (FILE *, SYS *);
  7420. Xextern void report_progress (FILE *, char *, int);
  7421. Xextern void setup_string (char *, char *, char *);
  7422. Xextern void init_signals (void);
  7423. Xextern void catch_signals (void);
  7424. Xextern void extract_origin (char *);
  7425. Xextern void extract_address (char *);
  7426. Xextern int  get_list_id (char *, SYS *, int);
  7427. Xextern void clean_request (char *);
  7428. Xextern int  _getopt (int, char **, char *);
  7429. Xextern char *upcase (char *);
  7430. Xextern char *locase (char *);
  7431. Xextern void shrink (char *);
  7432. Xextern void free_remote (REMOTE **);
  7433. Xextern void distribute (FILE *, void (*)(char *, char *, BOOLEAN, BOOLEAN),
  7434. X            FILE *, char *, char *, char *, char *, BOOLEAN);
  7435. Xextern BOOLEAN extract_subscriber (FILE *, char *, BOOLEAN);
  7436. Xextern BOOLEAN sysmail (char *);
  7437. Xextern BOOLEAN strinstr (char *, char *);
  7438. Xextern BOOLEAN ignore_sender (FILE *, char *, FILE *, BOOLEAN);
  7439. Xextern BOOLEAN owner_listed (char *, char *, char *, FILE *);
  7440. Xextern int  lock_file (char *, int, int, BOOLEAN);
  7441. Xextern void unlock_file (int);
  7442. Xextern int  otoi (char *);
  7443. Xextern BOOLEAN mkdir1 (char *, char *, char *);
  7444. Xextern BOOLEAN make_indexes (char *, char *, char *, char *, char *);
  7445. Xextern int  re_strcmp (char *, char *, char *);
  7446. Xextern char *_strstr (char *, char *);
  7447. Xextern char *skip_to_word (char *, int);
  7448. Xextern char *mystrdup (char *);
  7449. Xextern int echo (char *, char *);
  7450. Xextern int echo_append (char *, char *);
  7451. Xextern int mv (char *, char *);
  7452. Xextern int cp (char *, char *);
  7453. Xextern int cat_append (char *, char *);
  7454. Xextern int touch (char *);
  7455. Xextern int ucb_strftime (char *, int, char *, struct tm *);
  7456. Xextern long int write_to_fd (int, char *, long int);
  7457. Xextern void escape_re (char *);
  7458. Xextern int P (int, int);
  7459. Xextern int V (int, int);
  7460. X
  7461. Xvoid   main (int, char **, char **);
  7462. Xvoid   create_header (FILE **, char *, char *, char *, char *, char *,
  7463. X              BOOLEAN, BOOLEAN, BOOLEAN);
  7464. Xvoid   create_multi_recipient_header (FILE **, char *, char *, char *, char *,
  7465. X                      char *, int);
  7466. Xvoid   create_news_header (FILE **, char *, char *, char *, char *, char *);
  7467. Xvoid   create_gate_header (FILE **, char *, char *, char *, char *, char *,
  7468. X               char *);
  7469. Xvoid   process_message (char *, char *, BOOLEAN, BOOLEAN);
  7470. Xvoid   distributions (BOOLEAN, char *, char *, BOOLEAN, char *, char *,
  7471. X              char *, char *, char *, long int, BOOLEAN);
  7472. XBOOLEAN do_distribute (char *, FILE *, char *, BOOLEAN, char *, BOOLEAN, char *,
  7473. X               char *, char *, char *, char *, FILE *,
  7474. X               BOOLEAN, BOOLEAN, long int, BOOLEAN, BOOLEAN, BOOLEAN,
  7475. X               BOOLEAN);
  7476. XBOOLEAN unprocessed_users (char *, char *, FILE *);
  7477. Xvoid   update_unprocessed (char *, BOOLEAN, BOOLEAN, int);
  7478. Xvoid   update_unprocessed_messages (char *);
  7479. XBOOLEAN copy_msg (FILE *, char *, BOOLEAN, char *, long int, BOOLEAN, BOOLEAN);
  7480. XBOOLEAN sendmail (char *, BOOLEAN, BOOLEAN, int, int, char *);
  7481. Xvoid   usage (void);
  7482. Xvoid   list_config (char *);
  7483. Xvoid   version (void);
  7484. Xint    gexit (int);
  7485. Xvoid   fill_text (FILE *, char *);
  7486. XBOOLEAN read_recipient (FILE *, char *, char *, char *, BOOLEAN);
  7487. Xlong int count_lines_in_file (FILE *);
  7488. Xvoid   digest_make (BOOLEAN);
  7489. Xvoid   digest_distribute (void);
  7490. Xvoid   do_archive (char *, char *, char *, BOOLEAN);
  7491. Xvoid   farch (char *, char *, char *, char *, char *, char *);
  7492. Xvoid   reject_archive (char *, char *);
  7493. XBOOLEAN get_volume (char *, int *, int *);
  7494. XBOOLEAN get_archive_name (char *, char *);
  7495. XBOOLEAN limit_exceeded (char *, char *, char *);
  7496. X
  7497. X/*
  7498. X  The control structure of the mail-distributor. Check if mail has arrived.
  7499. X  If so, copy it to MAIL_COPY and proceed to lower level.
  7500. X*/
  7501. X
  7502. Xvoid main (int argc, char **argv, char **envp)
  7503. X{
  7504. X  struct stat stat_buf;
  7505. X  char *options = "1fvrL:em:spPDMdi:S:Z", tmp[MAX_LINE], error [MAX_LINE];
  7506. X  int rlfd, i, j, c;
  7507. X  long int sig_mask;
  7508. X  FILE *f;
  7509. X  extern char *optarg, *getenv();
  7510. X  extern int optopt;
  7511. X#ifdef TCP_IP
  7512. X  struct hostent *lhost;
  7513. X#endif
  7514. X
  7515. X  prog = argv[0];
  7516. X  while ((c = _getopt (argc, argv, options)) != EOF)
  7517. X    switch ((char) c) {
  7518. X      case '1': execute_once = TRUE; break;
  7519. X      case 'f': errors_to_owner = TRUE; break;
  7520. X      case 'r': send_to_subscribers = FALSE; break;
  7521. X      case 'L': list_alias = upcase (optarg); break;
  7522. X      case 'e': tty_echo = TRUE; break;
  7523. X      case 's': do_not_check_subscriptions = TRUE; break;
  7524. X      case 'S': sid = atoi (optarg); break;
  7525. X      case 'p': article_replies_to_author = TRUE; break;
  7526. X      case 'P': message_replies_to_author = TRUE; break;
  7527. X      case 'v': version ();
  7528. X      case 'D': debug = TRUE; break;
  7529. X      case 'd': force_digest = TRUE; break;
  7530. X      case 'i': one_digest = optarg; break;
  7531. X      case 'M': is_moderated = TRUE; break;
  7532. X      case 'm':
  7533. X    multi_recip = TRUE;
  7534. X    if ((maxrecipients = atoi (optarg)) < 1)
  7535. X      fprintf (stderr, "-m %d -- yeah, right!\n", maxrecipients),
  7536. X      exit (3);
  7537. X    break;
  7538. X      case 'Z': no_compression = TRUE; break;
  7539. X      case ':': 
  7540. X    fprintf (stderr, "list: Option '%c' requires an argument.\n", optopt);
  7541. X    exit (3);
  7542. X      case '?':
  7543. X      default:
  7544. X    usage ();
  7545. X    }
  7546. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  7547. X    umask (otoi (mask));
  7548. X  else
  7549. X    mask = "066",
  7550. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  7551. X  if (!(archives_mask = getenv ("ULISTPROC_ARCHIVES_UMASK")))
  7552. X    archives_mask = mask;
  7553. X  init_signals();
  7554. X  catch_signals();
  7555. X  list_config (list_alias);
  7556. X#ifdef SYSLOG
  7557. X  openlog ("ListProcessor: list", LOG_NDELAY
  7558. X# ifndef i386
  7559. X       |LOG_NOWAIT
  7560. X# endif
  7561. X       , SYSLOG);
  7562. X# ifndef ultrix
  7563. X  setlogmask (LOG_UPTO (LOG_INFO));
  7564. X# endif
  7565. X#else
  7566. X  if ((report = fopen (report_listf, "a")) == NULL)
  7567. X    if ((report = fopen (REPORT_LIST, "a")) == NULL)
  7568. X      fprintf (stderr, "list: Could not open %s and %s\n", report_listf,
  7569. X           REPORT_LIST),
  7570. X      exit (1);
  7571. X    else
  7572. X      chmod (REPORT_LIST, 384); /* 600 */
  7573. X  else
  7574. X    chmod (report_listf, 384); /* 600 */
  7575. X#endif
  7576. X  if (list_alias == NULL)
  7577. X    report_progress (report, "\nlist: No list to process", TRUE),
  7578. X    exit (3);
  7579. X  nlists = sys_config (report, &sys);
  7580. X  if ((listid = get_list_id (list_alias, &sys, nlists)) < 0)
  7581. X    report_progress (report, tsprintf ("\nlist: Unknown list %s", list_alias),
  7582. X             TRUE),
  7583. X    exit (3);
  7584. X  if (!execute_once)
  7585. X    printf ("%s", COPYRIGHT);
  7586. X  if (sys.options & USE_ENV_VAR) {
  7587. X    if ((sys.mail.method = (char *) malloc (256 * sizeof (char))) == NULL)
  7588. X      report_progress (report, "\nmain(): malloc() failed", TRUE),
  7589. X      exit (11);
  7590. X    sprintf (sys.mail.method, "env - %s=%s %s ", sys.mail.env_var,
  7591. X             sys.lists[listid].address, sys.mail.mail_prog);
  7592. X  }
  7593. X
  7594. X  if ((msg_no = fopen (msg_nof, "r")) != NULL)
  7595. X    fscanf (msg_no, "%d %d\n", &public_msg, &returned_msg),
  7596. X    fclose (msg_no);
  7597. X  if ((digest_no = fopen (digest_nof, "r")) != NULL)
  7598. X    fscanf (digest_no, "%d\n", &digest_msg),
  7599. X    fclose (digest_no);
  7600. X
  7601. X  if (!tty_echo) {
  7602. X    j = -1;
  7603. X#if defined (TIOCNOTTY) && defined (SIGTTOU) && defined (SIGTTIN)
  7604. X    if ((i = open ("/dev/tty", 2)) >= 0)
  7605. X      j = ioctl (i, TIOCNOTTY, 0),
  7606. X      close (i);
  7607. X#endif
  7608. X    if (j < 0 && 
  7609. X#ifdef svr4
  7610. X    setsid ()
  7611. X#else
  7612. X# ifdef SETPGRP_NEEDS_ARGS
  7613. X    setpgrp (0, 0) 
  7614. X# else
  7615. X    setpgrp ()
  7616. X# endif
  7617. X#endif 
  7618. X    < 0)
  7619. X      report_progress (report, "WARNING: could not detach from tty", TRUE);
  7620. X  }
  7621. X
  7622. X  if (multi_recip)
  7623. X    if ((multi_recipients = (char **) malloc (maxrecipients * sizeof (char *)))
  7624. X    == NULL)
  7625. X      report_progress (report, "\nmain(): malloc() failed", TRUE),
  7626. X      exit (11);
  7627. X
  7628. X  if ((f = fopen (PID_LIST, "w")) != NULL)
  7629. X    fprintf (f, "%d", getpid()),
  7630. X    fclose (f);
  7631. X  signal (SIGINT, (void (*)()) gexit);
  7632. X  signal (SIGALRM, SIG_IGN);
  7633. X#ifdef TCP_IP
  7634. X  if (gethostname (hostname, sizeof (hostname)))
  7635. X    report_progress (report, tsprintf ("\nmain(): gethostname() failed: errno \
  7636. X%d", errno), TRUE),
  7637. X    exit (16);
  7638. X  if (!(lhost = gethostbyname (hostname)))
  7639. X    report_progress (report, tsprintf ("\nmain(): gethostbyname() failed: errno\
  7640. X %d", errno), TRUE),
  7641. X    exit (16);
  7642. X  memcpy ((char *) &localaddr, (char *) lhost->h_addr, lhost->h_length);
  7643. X#else
  7644. X  localaddr = LOCAL_ADDR;
  7645. X  strcpy (hostname, HOSTNAME);
  7646. X#endif
  7647. X
  7648. X#ifdef GO_INTERACTIVE
  7649. X  IN_CRITICAL_SECTION ("main", SEM_LISTFILES);
  7650. X# ifndef ERROR_MAIL_ANALYSIS
  7651. X  sprintf (tmp, "%s.t", subscribersf);
  7652. X  if (cp (subscribersf, tmp))
  7653. X    gexit (16);
  7654. X  strcpy (subscribersf, tmp);
  7655. X  sprintf (tmp, "%s.t", newsf);
  7656. X  if (cp (newsf, tmp))
  7657. X    gexit (16);
  7658. X  strcpy (newsf, tmp);
  7659. X  sprintf (tmp, "%s.t", peersf);
  7660. X  if (cp (peersf, tmp))
  7661. X    gexit (16);
  7662. X  strcpy (peersf, tmp);
  7663. X  OUT_OF_CRITICAL_SECTION ("main", SEM_LISTFILES);
  7664. X# endif
  7665. X  IN_CRITICAL_SECTION ("main", SEM_DLVR_MAIL);
  7666. X#endif
  7667. X
  7668. X  sprintf (error, "recipients of digest %d", digest_msg);
  7669. X  if (unprocessed_users (unprocessed_digestf, error, report)) {
  7670. X    /* Was interrupted while distributing a digest */
  7671. X    /* USER CONTIBUTED CODE: Warren Burstein */
  7672. X    OPEN_FILE (subscribers, subscribersf, "r", "main");
  7673. X    OPEN_FILE (news, newsf, "r", "main");
  7674. X    OPEN_FILE (peers, peersf, "r", "main");
  7675. X    OPEN_FILE (restricted, restrictedf, "r", "main");
  7676. X
  7677. X    digest_distribute ();
  7678. X
  7679. X    fclose (subscribers);
  7680. X    fclose (news);
  7681. X    fclose (peers);
  7682. X    fclose (restricted);
  7683. X  }
  7684. X
  7685. X  if ((force_digest || one_digest) &&
  7686. X      (!stat (digest_msgf, &stat_buf) && stat_buf.st_size > 0)) {
  7687. X    OPEN_FILE (subscribers, subscribersf, "r", "main");
  7688. X    OPEN_FILE (news, newsf, "r", "main");
  7689. X    OPEN_FILE (peers, peersf, "r", "main");
  7690. X    OPEN_FILE (restricted, restrictedf, "r", "main");
  7691. X
  7692. X    if (force_digest) {
  7693. X      digest_make (TRUE);
  7694. X      digest_distribute ();
  7695. X    }
  7696. X    else { /* Make a partial digest, send to one_digest */
  7697. X      char subject[MAX_LINE];
  7698. X      FILE *forwardmail = NULL; /* Completed message to be forwarded */
  7699. X
  7700. X      digest_make (FALSE);
  7701. X
  7702. X      sprintf (subject, "%s partial digest %d", sys.lists[listid].alias,
  7703. X           digest_msg);
  7704. X
  7705. X      create_header (&forwardmail, mailforwardf, sys.lists[listid].address,
  7706. X             sys.lists[listid].address, one_digest, subject,
  7707. X             FALSE, FALSE, FALSE);
  7708. X      if (copy_msg (forwardmail, msgf, FALSE, sys.lists[listid].address, 0,
  7709. X            FALSE, FALSE))
  7710. X        sendmail (one_digest, FALSE, FALSE, 0, 0, mailforwardf);
  7711. X    }
  7712. X    fclose (subscribers);
  7713. X    fclose (news);
  7714. X    fclose (peers);
  7715. X    fclose (restricted);
  7716. X  }
  7717. X
  7718. X  do {
  7719. X    if (!stat (list_mail_f, &stat_buf) && stat_buf.st_size > 0) {
  7720. X#ifdef bsd
  7721. X      sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  7722. X#elif defined (svr4) || defined (svr3)
  7723. X      sighold (SIGINT);
  7724. X      sighold (SIGTERM);
  7725. X#endif
  7726. X#ifndef NO_LOCKS
  7727. X      if ((rlfd = lock_file (list_mail_f, O_RDWR, 0, FALSE)) < 0)
  7728. X    report_progress (report, tsprintf ("\nmain(): Cannot open or lock %s",
  7729. X                       list_mail_f), TRUE),
  7730. X    gexit (1); /* Cannot lock file, so exit, regardless of execute_once */
  7731. X#endif
  7732. X      if (!sys.lists[listid].max_messages) {
  7733. X    if (cp (list_mail_f, mail_copyf))
  7734. X      exit (16);
  7735. X    unlink (list_mail_f);
  7736. X    touch (list_mail_f); /* rewrite file */
  7737. X    chmod (list_mail_f, /*416*/ 0666 & (0666 ^ otoi (mask)));
  7738. X      }
  7739. X      else if (limit_exceeded (limitsf, list_mail_f, mail_copyf)) {
  7740. X#ifndef NO_LOCKS
  7741. X        unlock_file (rlfd);
  7742. X#endif
  7743. X    break;
  7744. X      }
  7745. X      if (cat_append (mail_copyf, mboxf))
  7746. X    exit (16);
  7747. X      chmod (mboxf, 384);
  7748. X      if (cp (mail_copyf, unprocessed_messages))
  7749. X    exit (16);
  7750. X      echo_append ("", mboxf);
  7751. X      touch (list_moderated_f);
  7752. X      chmod (list_moderated_f, /*416*/ 0666 & (0666 ^ otoi (mask)));
  7753. X
  7754. X#ifndef NO_LOCKS
  7755. X      unlock_file (rlfd);
  7756. X#endif
  7757. X#ifdef bsd
  7758. X      sigsetmask (sig_mask);
  7759. X#elif defined (svr4) || defined (svr3)
  7760. X      sigrelse (SIGINT);
  7761. X      sigrelse (SIGTERM);
  7762. X#endif
  7763. X
  7764. X      OPEN_FILE (mail, mail_copyf, "r", "main");
  7765. X      OPEN_FILE (subscribers, subscribersf, "r", "main");
  7766. X      OPEN_FILE (news, newsf, "r", "main");
  7767. X      OPEN_FILE (peers, peersf, "r", "main");
  7768. X      OPEN_FILE (restricted, restrictedf, "r", "main");
  7769. X      OPEN_FILE (ignored, ignoredf, "r", "main");
  7770. X      OPEN_FILE (headers, headersf, "a", "main");
  7771. X      report_progress (report, NEW_ARRIVAL, FALSE);
  7772. X      distribute (mail,
  7773. X          (void (*)(char *, char *, BOOLEAN, BOOLEAN)) process_message,
  7774. X          report, subscribersf, newsf, peersf, aliasesf,
  7775. X#ifdef ERROR_MAIL_ANALYSIS
  7776. X          FALSE
  7777. X#else
  7778. X          TRUE
  7779. X#endif
  7780. X          );
  7781. X      fclose (mail);  /* Done */
  7782. X      fclose (subscribers);
  7783. X      fclose (news);
  7784. X      fclose (peers);
  7785. X      fclose (restricted);
  7786. X      fclose (ignored);
  7787. X      fclose (headers);
  7788. X      shrink (message_idsf);
  7789. X      shrink (checksumsf);
  7790. X      unlink (unprocessed_messages);
  7791. X      unlink (mail_copyf);  /* Done delivering */
  7792. X    }
  7793. X    else if (!execute_once) /* No mail to deliver */
  7794. X      if (sys.frequency > 0)
  7795. X        sleep (sys.frequency);
  7796. X  } while (!execute_once);
  7797. X#ifdef GO_INTERACTIVE
  7798. X# ifndef ERROR_MAIL_ANALYSIS
  7799. X  unlink (subscribersf);
  7800. X  unlink (newsf);
  7801. X  unlink (peersf);
  7802. X# else
  7803. X  OUT_OF_CRITICAL_SECTION ("main", SEM_LISTFILES);
  7804. X# endif
  7805. X  OUT_OF_CRITICAL_SECTION ("main", SEM_DLVR_MAIL);
  7806. X#endif
  7807. X#ifdef bsd
  7808. X  sigsetmask (sig_mask);
  7809. X#elif defined (svr4) || defined (svr3)
  7810. X  sigrelse (SIGINT);
  7811. X  sigrelse (SIGTERM);
  7812. X#endif
  7813. X#ifdef SYSLOG
  7814. X  closelog ();
  7815. X#else
  7816. X  fclose (report);
  7817. X#endif
  7818. X  free_remote (&rlists);
  7819. X  if (multi_recip)
  7820. X    free ((char **) multi_recipients);
  7821. X  unlink (PID_LIST);
  7822. X  exit (0);
  7823. X}
  7824. X
  7825. X/* 
  7826. X  Create a mail header. If this is a reply to a rejected posting, 'copy_owner'
  7827. X  should be TRUE. If reply_to_sender is TRUE, message will reply to sender,
  7828. X  otherwise to list.
  7829. X*/
  7830. X
  7831. Xvoid create_header (FILE **f, char *filename, char *sender, char *originator,
  7832. X            char *recipient, char *subject, BOOLEAN copy_owner,
  7833. X            BOOLEAN reply_to_sender, BOOLEAN error_condition)
  7834. X{
  7835. X  char error [MAX_LINE];
  7836. X  char origin [MAX_LINE];
  7837. X  char reply_to [MAX_LINE];
  7838. X#ifdef LIST_ALIAS_IN_SUBJECT
  7839. X  char *s, *sb;
  7840. X#endif
  7841. X#ifdef NEED_DATE
  7842. X  char date [80];
  7843. X# ifdef ultrix
  7844. X  time_t time_is;
  7845. X# else
  7846. X  long int time_is;
  7847. X# endif
  7848. X  struct tm *t;
  7849. X#endif
  7850. X  MATCHED_PREC_HEADER *m = matched_prec_header;
  7851. X
  7852. X  strcpy (origin, originator);
  7853. X  locase (origin);
  7854. X  strcpy (reply_to, sender);
  7855. X  extract_address (reply_to);
  7856. X  OPEN_FILE (*f, filename, "w", "create_header");
  7857. X  locase (recipient);
  7858. X  if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
  7859. X    subject [strlen (subject) - 1] = EOS;
  7860. X  if (sys.options & USE_TELNET) {
  7861. X    fprintf (*f, "HELO %s\nMAIL From: <%s>\nRCPT To: <%s>\n",
  7862. X#ifdef ZMAILER
  7863. X/*
  7864. X# ifdef TCP_IP
  7865. X         (char *) inet_ntoa (localaddr),
  7866. X# else
  7867. X         localaddr,
  7868. X# endif
  7869. X    Use either the local address or the host name.
  7870. X*/
  7871. X         hostname,
  7872. X#else
  7873. X         "",
  7874. X#endif
  7875. X         sys.lists[listid].address, recipient);
  7876. X    if (copy_owner)
  7877. X      fprintf (*f, "RCPT To: <%s>\n", sys.lists[listid].owner);
  7878. X    fprintf (*f, "DATA\n");
  7879. X  }
  7880. X  if (message_id[0] != EOS)
  7881. X    fprintf (*f, "Message-Id: %s\n", message_id);
  7882. X#ifdef NEED_DATE
  7883. X  time (&time_is);
  7884. X  t = localtime (&time_is);
  7885. X  ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
  7886. X  fprintf (*f, "Date: %s\n", date);
  7887. X#endif
  7888. X#ifndef NO_ERRORS_TO
  7889. X  fprintf (*f, "Errors-To: %s\n", sys.lists[listid].owner);
  7890. X#endif
  7891. X  while (m) {
  7892. X    if (!strncmp ("Reply-To:", m->line, strlen ("Reply-To:")))
  7893. X      break;
  7894. X    m = m->next;
  7895. X  }
  7896. X  if (!m)
  7897. X    fprintf (*f, "Reply-To: %s\n",
  7898. X         ((reply_to_sender | message_replies_to_author) ? 
  7899. X          reply_to : sys.lists[listid].address));
  7900. X  fprintf (*f, "Originator: %s\nSender: %s\nPrecedence: %s\nFrom: %s\nTo: %s\n",
  7901. X       origin, sys.lists[listid].address, sys.mail.precedence, sender,
  7902. X       recipient);
  7903. X  if (copy_owner)
  7904. X    fprintf (*f, "Cc: %s\n", sys.lists[listid].owner);
  7905. X#ifdef LIST_ALIAS_IN_SUBJECT
  7906. X  if (!error_condition) {
  7907. X    /* Remove previous tag and amassing Re: */
  7908. X    if ((s = _strstr (subject, tsprintf ("[%s:", sys.lists[listid].alias)))) {
  7909. X      sprintf (s, "%s", ((sb = strchr (s, ']')) ? sb + 2 : ""));
  7910. X      if (re_strcmp ("^[ \t]*[Rr][Ee]:[ \t]+[Rr][Ee]:", subject, NULL) > 0)
  7911. X    sprintf (subject, "%s", subject + 4);
  7912. X    }
  7913. X    fprintf (*f, "Subject: [%s:%d] %s\n", sys.lists[listid].alias, public_msg,
  7914. X         subject);
  7915. X  }
  7916. X  else
  7917. X    fprintf (*f, "Subject: %s%s\n", ERROR_CONDITION, subject);
  7918. X#else
  7919. X  fprintf (*f, "Subject: %s%s\n", (error_condition ? ERROR_CONDITION : ""),
  7920. X       subject);
  7921. X#endif
  7922. X  fprintf (*f, "X-Listprocessor-Version: %s\n", VERSION);
  7923. X  if (sys.lists[listid].comment[0] != EOS)
  7924. X    fprintf (*f, "X-Comment: %s\n", sys.lists[listid].comment);
  7925. X  m = matched_prec_header;
  7926. X  while (m)
  7927. X    fprintf (*f, "%s", m->line),
  7928. X    m = m->next;
  7929. X  fprintf (*f, "\n");
  7930. X}
  7931. X
  7932. X/* 
  7933. X  Create a mail header with multiple recipients.
  7934. X*/
  7935. X
  7936. Xvoid create_multi_recipient_header (FILE **f, char *filename, char *sender,
  7937. X                    char *originator, char *recipient,
  7938. X                    char *subject, int nrecipients)
  7939. X{
  7940. X  char origin [MAX_LINE];
  7941. X  char reply_to [MAX_LINE];
  7942. X  int  i;
  7943. X  MATCHED_PREC_HEADER *m = matched_prec_header;
  7944. X#ifdef LIST_ALIAS_IN_SUBJECT
  7945. X  char *s, *sb;
  7946. X#endif
  7947. X#ifdef NEED_DATE
  7948. X  char date [80];
  7949. X# ifdef ultrix
  7950. X  time_t time_is;
  7951. X# else
  7952. X  long int time_is;
  7953. X# endif
  7954. X  struct tm *t;
  7955. X#endif
  7956. X
  7957. X  strcpy (origin, originator);
  7958. X  locase (origin);
  7959. X  strcpy (reply_to, sender);
  7960. X  extract_address (reply_to);
  7961. X  if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
  7962. X    subject [strlen (subject) - 1] = EOS;
  7963. X  OPEN_FILE (*f, filename, "w", "create_multi_recipient_header");
  7964. X  if (sys.options & USE_TELNET) {
  7965. X    fprintf (*f, "HELO %s\nMAIL From: <%s>\n",
  7966. X#ifdef ZMAILER
  7967. X/*
  7968. X# ifdef TCP_IP
  7969. X         (char *) inet_ntoa (localaddr),
  7970. X# else
  7971. X         localaddr,
  7972. X# endif
  7973. X    Use either the local address or the host name.
  7974. X*/
  7975. X         hostname,
  7976. X#else
  7977. X         "",
  7978. X#endif
  7979. X         sys.lists[listid].address);
  7980. X    for (i = 0; i < nrecipients; i++)
  7981. X      fprintf (*f, "RCPT To: <%s>\n", multi_recipients[i]),
  7982. X      free ((char *) multi_recipients[i]);
  7983. X    fprintf (*f, "DATA\n");
  7984. X  }
  7985. X  if (message_id[0] != EOS)
  7986. X    fprintf (*f, "Message-Id: %s\n", message_id);
  7987. X#ifdef NEED_DATE
  7988. X  time (&time_is);
  7989. X  t = localtime (&time_is);
  7990. X  ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
  7991. X  fprintf (*f, "Date: %s\n", date);
  7992. X#endif
  7993. X#ifndef NO_ERRORS_TO
  7994. X  fprintf (*f, "Errors-To: %s\n", sys.lists[listid].owner);
  7995. X#endif
  7996. X  while (m) {
  7997. X    if (!strncmp ("Reply-To:", m->line, strlen ("Reply-To:")))
  7998. X      break;
  7999. X    m = m->next;
  8000. X  }
  8001. X  if (!m)
  8002. X    fprintf (*f, "Reply-To: %s\n",
  8003. X         (message_replies_to_author ? reply_to : sys.lists[listid].address));
  8004. X  fprintf (*f, "Originator: %s\nSender: %s\nPrecedence: %s\nFrom: %s\nTo: %s\n",
  8005. X       origin, sys.lists[listid].address, sys.mail.precedence, sender,
  8006. X       recipient);
  8007. X#ifdef LIST_ALIAS_IN_SUBJECT
  8008. X  /* Remove previous tag and amassing Re: */
  8009. X  if ((s = _strstr (subject, tsprintf ("[%s:", sys.lists[listid].alias)))) {
  8010. X    sprintf (s, "%s", ((sb = strchr (s, ']')) ? sb + 2 : ""));
  8011. X    if (re_strcmp ("^[ \t]*[Rr][Ee]:[ \t]+[Rr][Ee]:", subject, NULL) > 0)
  8012. X      sprintf (subject, "%s", subject + 4);
  8013. X  }
  8014. X  fprintf (*f, "Subject: [%s:%d] %s\n", sys.lists[listid].alias, public_msg,
  8015. X       subject);
  8016. X#else
  8017. X  fprintf (*f, "Subject: %s\n", subject);
  8018. X#endif
  8019. X  fprintf (*f, "X-Listprocessor-Version: %s\n", VERSION);
  8020. X  if (sys.lists[listid].comment[0] != EOS)
  8021. X    fprintf (*f, "X-Comment: %s\n", sys.lists[listid].comment);
  8022. X  m = matched_prec_header;
  8023. X  while (m)
  8024. X    fprintf (*f, "%s", m->line),
  8025. X    m = m->next;
  8026. X  fprintf (*f, "\n");
  8027. X}
  8028. X
  8029. X/*
  8030. X  Create a news header for a message to be posted.
  8031. X*/
  8032. X
  8033. Xvoid create_news_header (FILE **f, char *filename, char *sender,
  8034. X             char *originator, char *group, char *subject)
  8035. X{
  8036. X  char origin [MAX_LINE];
  8037. X  char reply_to [MAX_LINE];
  8038. X  MATCHED_PREC_HEADER *m = matched_prec_header;
  8039. X#ifdef NEED_DATE
  8040. X  char date [80];
  8041. X# ifdef ultrix
  8042. X  time_t time_is;
  8043. X# else
  8044. X  long int time_is;
  8045. X# endif
  8046. X  struct tm *t;
  8047. X#endif
  8048. X
  8049. X  strcpy (origin, originator);
  8050. X  locase (origin);
  8051. X  strcpy (reply_to, sender);
  8052. X  extract_address (reply_to);
  8053. X  if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
  8054. X    subject [strlen (subject) - 1] = EOS;
  8055. X  OPEN_FILE (*f, filename, "w", "create_news_header");
  8056. X  locase (group);
  8057. X  fprintf (*f, "Path: %s\nNewsgroups: %s\nDistribution: world\n\
  8058. XOrganization: %s\nOriginator: %s\n",
  8059. X       (article_replies_to_author ? reply_to : sys.lists[listid].address),
  8060. X       group, sys.organization, origin);
  8061. X  if (message_id[0] != EOS)
  8062. X    fprintf (*f, "Message-Id: %s\n", message_id);
  8063. X#ifdef NEED_DATE
  8064. X  time (&time_is);
  8065. X  t = localtime (&time_is);
  8066. X  ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
  8067. X  fprintf (*f, "Date: %s\n", date);
  8068. X#endif
  8069. X  while (m) {
  8070. X    if (!strncmp ("Reply-To:", m->line, strlen ("Reply-To:")))
  8071. X      break;
  8072. X    m = m->next;
  8073. X  }
  8074. X  if (!m)
  8075. X    fprintf (*f, "Reply-To: %s\n",
  8076. X         (article_replies_to_author ? reply_to : sys.lists[listid].address));
  8077. X  fprintf (*f, "Sender: %s\nFrom: %s\nSubject: %s\n", 
  8078. X       sys.lists[listid].address, sender, subject);
  8079. X  m = matched_prec_header;
  8080. X  while (m)
  8081. X    fprintf (*f, "%s", m->line),
  8082. X    m = m->next;
  8083. X  fprintf (*f, "\n");
  8084. X}
  8085. X
  8086. X/*
  8087. X  Create a gateway header.
  8088. X*/
  8089. X
  8090. Xvoid create_gate_header (FILE **f, char *filename, char *sender,
  8091. X             char *originator, char *recipient, 
  8092. X             char *group, char *subject)
  8093. X{
  8094. X  char origin [MAX_LINE];
  8095. X  char reply_to [MAX_LINE];
  8096. X  MATCHED_PREC_HEADER *m = matched_prec_header;
  8097. X#ifdef NEED_DATE
  8098. X  char date [80];
  8099. X# ifdef ultrix
  8100. X  time_t time_is;
  8101. X# else
  8102. X  long int time_is;
  8103. X# endif
  8104. X  struct tm *t;
  8105. X#endif
  8106. X
  8107. X  strcpy (origin, originator);
  8108. X  locase (origin);
  8109. X  strcpy (reply_to, sender);
  8110. X  extract_address (reply_to);
  8111. X  if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
  8112. X    subject [strlen (subject) - 1] = EOS;
  8113. X  OPEN_FILE (*f, filename, "w", "create_gate_header");
  8114. X  locase (group);
  8115. X  if (sys.options & USE_TELNET)
  8116. X    fprintf (*f, "HELO %s\nMAIL From: <%s>\nRCPT To: <%s>\nDATA\n",
  8117. X#ifdef ZMAILER
  8118. X/*
  8119. X# ifdef TCP_IP
  8120. X         (char *) inet_ntoa (localaddr),
  8121. X# else
  8122. X         localaddr,
  8123. X# endif
  8124. X    Use either the local address or the host name.
  8125. X*/
  8126. X         hostname,
  8127. X#else
  8128. X         "",
  8129. X#endif
  8130. X         sys.lists[listid].address, recipient);
  8131. X#ifndef NO_ERRORS_TO
  8132. X  fprintf (*f, "Errors-To: %s\n", sys.lists[listid].owner);
  8133. X#endif
  8134. X  fprintf (*f, "Newsgroups: %s\nDistribution: world\nOrganization: %s\n\
  8135. XOriginator: %s\n", group, sys.organization, origin);
  8136. X  if (message_id[0] != EOS)
  8137. X    fprintf (*f, "Message-Id: %s\n", message_id);
  8138. X#ifdef NEED_DATE
  8139. X  time (&time_is);
  8140. X  t = localtime (&time_is);
  8141. X  ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
  8142. X  fprintf (*f, "Date: %s\n", date);
  8143. X#endif
  8144. X  while (m) {
  8145. X    if (!strncmp ("Reply-To:", m->line, strlen ("Reply-To:")))
  8146. X      break;
  8147. X    m = m->next;
  8148. X  }
  8149. X  if (!m)
  8150. X    fprintf (*f, "Reply-To: %s\n",
  8151. X         (article_replies_to_author ? reply_to : sys.lists[listid].address));
  8152. X  fprintf (*f, "Sender: %s\nFrom: %s\nTo: %s\nSubject: %s\n",
  8153. X       sys.lists[listid].address, sender, recipient, subject);
  8154. X  m = matched_prec_header;
  8155. X  while (m)
  8156. X    fprintf (*f, "%s", m->line),
  8157. X    m = m->next;
  8158. X  fprintf (*f, "\n");
  8159. X}
  8160. X
  8161. X/*
  8162. X  The heart of the distribution. Since we are now at the beginning of the
  8163. X  message (as guaranteed by distribute ()), gather the rest of the message
  8164. X  -- that is until the beginning of the next message, or EOF. Note that
  8165. X  only the "From: ", "Originator: " and "Subject: " lines from the header
  8166. X  are saved.
  8167. X  The beginning of the next and every message is "From ". The actual
  8168. X  text of each message is separated from its header by a blank line (universal
  8169. X  format). The message is processed only if the sender is not listed in
  8170. X  IGNORED.
  8171. X  The entire message is stored in MSG. To distribute the message, prepare
  8172. X  a new header; the completed message is stored in MAILFORWARD. Actually,
  8173. X  for each subscriber we prepare a different header (different "To:" field) 
  8174. X  and append MSG to MAILFORWARD. Distribute that mail to the members,
  8175. X  or, either return it to the sender if he/she is not subscribed, or
  8176. X  forward it to MANAGER if -f specified. Messages from MAILER_DAEMON are
  8177. X  always forwarded to MANAGER. A message from a mailer daemon is identified
  8178. X  by the presence of MAILER_DAEMON anywhere in the sender's email address,
  8179. X  to cover local and remote mailer daemon addresses. Please look at the
  8180. X  documentation for defs.h for the syntax of the MAILER_DAEMON string.
  8181. X  The parameter "sender" is used for report purposes and when we are sending
  8182. X  the sender's message back to him/her.
  8183. X  Messages from regular subscribers are sent to peer lists and news groups.
  8184. X  Messages from news groups are only distributed to local subscribers and
  8185. X  peer lists. Finally, messages from peer lists are distributed locally
  8186. X  and may be posted to news groups.
  8187. X  In the case of restricted mail, check if the sender is listed in 
  8188. X  RESTRICTED; if so, forward the message to the people listed in the
  8189. X  filename found after the restricted-sender's address in RESTRICTED.
  8190. X  Each public message (legitimate message) is automatically archived.
  8191. X*/
  8192. X
  8193. Xchar *msgs[] = { /* USER CONTRIBUTED CODE: Warren Burstein */
  8194. X    "If you forward it back to the list, it will be distributed without the",
  8195. X    "paragraphs above the dashed line.  You may edit the Subject: line and",
  8196. X    "the text of the message before forwarding it back.",
  8197. X    "",
  8198. X    "If you edit the messages you receive into a digest, you will need to",
  8199. X    "remove these paragraphs and the dashed line before mailing the result", 
  8200. X    "to the list. Finally, if you need more information from the author of",
  8201. X    "this message, you should be able to do so by simply replying to this",
  8202. X    "note.",
  8203. X    "", NULL
  8204. X};
  8205. X
  8206. Xvoid process_message (char *sender, char *linecopy, BOOLEAN address_ok,
  8207. X              BOOLEAN sender_subscribed)
  8208. X{
  8209. X  char line [MAX_LINE];            /* ... from the current message */
  8210. X  char sent_date [MAX_LINE];
  8211. X  char senders_subject [MAX_LINE]; /* the sender's subject */
  8212. X  char subject_copy [MAX_LINE];    /* a copy of the subject */
  8213. X  char original_sender [MAX_LINE]; /* as it appears in his message */
  8214. X  char originator [MAX_LINE];       /* Holds the Originator: address */
  8215. X  char reply_to [MAX_LINE];       /* Holds the Reply-To: address */
  8216. X  char id_copy [MAX_LINE];       /* Holds the Message-Id: */
  8217. X  char recipients [MAX_LINE];       /* Holds the To: addresses */
  8218. X  char ccrecipients [MAX_LINE];       /* Holds the Cc: addresses */
  8219. X  char keywords [MAX_LINE];       /* Holds the Keywords: */
  8220. X  char precedence [MAX_LINE];       /* Holds the Precedence: */
  8221. X  char match [MAX_LINE];
  8222. X  char match2 [MAX_LINE];
  8223. X  char error [MAX_LINE];
  8224. X  char received [MAX_LINE];
  8225. X  char sender_copy [MAX_LINE];
  8226. X  char *at = NULL;
  8227. X  char *sumf = NULL;
  8228. X  char sum [MAX_LINE];
  8229. X  FILE *forwardmail = NULL;        /* completed message to be forwarded */
  8230. X  FILE *msg = NULL;
  8231. X  FILE *header = NULL;
  8232. X  FILE *in, *out, *f;
  8233. X  BOOLEAN already_sent = FALSE;
  8234. X  BOOLEAN message_forwarded = FALSE;
  8235. X  BOOLEAN mailer_daemon;
  8236. X  BOOLEAN susp_subject;
  8237. X  BOOLEAN fake_mail = TRUE;
  8238. X  BOOLEAN control_article = FALSE;
  8239. X  long int lines_to_skip = 0;      /* skip lines of incoming message */
  8240. X  long int sig_mask;
  8241. X  MATCHED_PREC_HEADER *out_header = matched_prec_header;
  8242. X  PRECIOUS_HEADER *pheader;
  8243. X  int request_found, i;
  8244. X
  8245. X  /* gets set if anyone wants digests */
  8246. X  append_to_digest = sys.lists[listid].options & ARCHIVE_DIGEST;
  8247. X
  8248. X  line[0] = sent_date[0] = recipients[0] = ccrecipients[0] = keywords[0] =
  8249. X    senders_subject[0] = subject_copy[0] = originator[0] = archive_name[0] =
  8250. X      reply_to[0] = message_id[0] = id_copy[0] = received[0] = precedence[0] =
  8251. X    RESET (original_sender);
  8252. X
  8253. X  strcpy (sender_copy, sender);
  8254. X  upcase (sender_copy);
  8255. X  while (matched_prec_header)    /* Free previous precious header lines */
  8256. X    out_header = matched_prec_header->next,
  8257. X    free ((char *) matched_prec_header->line),
  8258. X    free ((MATCHED_PREC_HEADER *) matched_prec_header),
  8259. X    matched_prec_header = out_header;
  8260. X
  8261. X  /* Remove message header, but store the "From: " and "Subject: " fields to
  8262. X     be used later when sending the message to all subscribers. Also, preserve
  8263. X     user-defined header lines. */
  8264. X
  8265. X  OPEN_FILE (header, headerf, "w", "process_message");
  8266. X  fprintf (header, "%s", linecopy);
  8267. X  while (!feof (mail) && line[0] != '\n') {
  8268. X    strcpy (match, "\\1");
  8269. X    if (re_strcmp (FROM, line, match) > 0) {
  8270. X      strcpy (original_sender, line + strlen (match)); /* Save From: */
  8271. X      original_sender [strlen (original_sender) - 1] = EOS; /* \n -> \0 */
  8272. X      if (strchr (original_sender, '|') || original_sender[0] == ':' ||
  8273. X      strchr (original_sender, '`'))
  8274. X    original_sender[0] = EOS;    /* protect against Trojans */
  8275. X    }
  8276. X
  8277. X    else if (re_strcmp (DATE, line, match) > 0)
  8278. X      strcpy (sent_date, line + strlen (match)), /* Save Date: */
  8279. X      sent_date [strlen (sent_date) - 1] = EOS;  /* \n -> \0 */
  8280. X
  8281. X    else if (re_strcmp (TO, line, match) > 0)
  8282. X      strcpy (recipients, line + strlen (match)), /* Save To: */
  8283. X      recipients [strlen (recipients) - 1] = EOS; /* \n -> \0 */
  8284. X
  8285. X    else if (re_strcmp (CC, line, match) > 0)
  8286. X      strcpy (ccrecipients, line + strlen (match)), /* Save Cc: */
  8287. X      ccrecipients [strlen (ccrecipients) - 1] = EOS; /* \n -> \0 */
  8288. X
  8289. X    else if (re_strcmp (KEYWORDS, line, match) > 0)
  8290. X      strcpy (keywords, line + strlen (match)), /* Save Keywords: */
  8291. X      keywords [strlen (keywords) - 1] = EOS; /* \n -> \0 */
  8292. X
  8293. X    else if (re_strcmp (SUBJECT, line, match) > 0) {
  8294. X      strcpy (senders_subject, line + strlen (match)); /* Save Subject: */
  8295. X      senders_subject [strlen (senders_subject) - 1] = EOS; /* \n -> \0 */
  8296. X      while (isspace (senders_subject[0]))
  8297. X    sprintf (senders_subject, "%s", senders_subject + 1);
  8298. X      strcpy (subject_copy, senders_subject);
  8299. X    }
  8300. X
  8301. X    else if (re_strcmp (ORIGIN, line, match) > 0)
  8302. X      strcpy (originator, line + strlen (match)),  /* Remove "Originator: " */
  8303. X      originator [strlen (originator) - 1] = EOS, /* \n -> \0 */
  8304. X      extract_origin (originator),
  8305. X      upcase (originator);
  8306. X
  8307. X    else if (re_strcmp (ARCHIVE_NAME, line, match) > 0)
  8308. X      /* Remove "Archive-Name: " */
  8309. X      strcpy (archive_name, line + strlen (match)),
  8310. X      extract_origin (archive_name);
  8311. X
  8312. X    else if (re_strcmp (REPLY_TO, line, match) > 0)
  8313. X      strcpy (reply_to, line + strlen (match)), /* Remove "Reply-To: " */
  8314. X      reply_to [strlen (reply_to) - 1] = EOS, /* \n -> \0 */
  8315. X      extract_origin (reply_to),
  8316. X      upcase (reply_to);
  8317. X
  8318. X    else if (re_strcmp (PRECEDENCE, line, match) > 0)
  8319. X      strcpy (precedence, line + strlen (match)), /* Remove "Precedence: " */
  8320. X      precedence [strlen (precedence) - 1] = EOS, /* \n -> \0 */
  8321. X      upcase (precedence);
  8322. X
  8323. X    else if (re_strcmp (RECEIVED, line, match) > 0) { /* Check for fake mail */
  8324. X      strcpy (received, line + strlen (match));
  8325. X      received [strlen (received) - 1] = EOS;
  8326. X      sscanf (received, "%s %s", error, received); /* Get host after "from" */
  8327. X      upcase (received);  /* Relay host */
  8328. X      if (fake_mail && (at = strchr (sender_copy + 1, '@')))
  8329. X    if (re_strcmp (at + 1, received, NULL) > 0)
  8330. X      fake_mail = FALSE;
  8331. X    }
  8332. X
  8333. X    else if (re_strcmp (CONTROL, line, NULL) > 0)
  8334. X      control_article = TRUE;
  8335. X
  8336. X    else if (re_strcmp (MESSAGE_ID1, line, NULL) > 0 ||
  8337. X             re_strcmp (MESSAGE_ID2, line, NULL) > 0 ||
  8338. X         re_strcmp (MESSAGE_ID3, line, NULL) > 0)
  8339. X      strcpy (message_id, line + strlen ("Message-") + 4),
  8340. X      message_id [strlen (message_id) - 1] = EOS; /* \n -> \0 */
  8341. X
  8342. X    else {    /* Check if precious header line */
  8343. X      pheader = sys.lists[listid].header;
  8344. X      while (pheader) {
  8345. X        if (!strncmp (line, pheader->line, strlen (pheader->line))) {
  8346. X      if (! (out_header =
  8347. X         (MATCHED_PREC_HEADER *) malloc (sizeof (MATCHED_PREC_HEADER))))
  8348. X        report_progress (report, "\nprocess_message(): malloc() failed",
  8349. X                 TRUE),
  8350. X        gexit (11);
  8351. X      if (! (out_header->line =
  8352. X         (char *) malloc ((strlen (line) + 1) * sizeof (char ))))
  8353. X        report_progress (report, "\nprocess_message(): malloc() failed",
  8354. X                 TRUE),
  8355. X        gexit (11);
  8356. X      strcpy (out_header->line, line);
  8357. X      out_header->next = matched_prec_header;
  8358. X      matched_prec_header = out_header;
  8359. X    }
  8360. X    pheader = pheader->next;
  8361. X      }
  8362. X    }
  8363. X
  8364. X    RESET (line);
  8365. X    fgets (line, MAX_LINE - 2, mail);
  8366. X    fprintf (header, "%s", line);
  8367. X  }
  8368. X  fclose (header);
  8369. X
  8370. X  /* Gather message into MSG; check if we have reached the next message, 
  8371. X     or EOF; also check for possible requests sent to the list */
  8372. X  OPEN_FILE (msg, msgf, "w", "process_message");
  8373. X  RESET (line);
  8374. X  request_found = -1;
  8375. X  while (!feof (mail) && 
  8376. X     (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
  8377. X    if (!strcmp (line, ".\n"))
  8378. X      PREPEND (".", line);
  8379. X    fprintf (msg, "%s", line);
  8380. X    upcase (line);
  8381. X    if (line [0] != EOS && line [strlen (line) - 1] == '\n')
  8382. X      line [strlen (line) - 1] = EOS;
  8383. X    if (request_found < 0 && line[0] != EOS) { /* First non-empty line */
  8384. X      strcpy (match, "\\1");
  8385. X      if (re_strcmp (REQUESTS, line, match) > 0) { /* Possible request */
  8386. X#ifdef LIST_CHECKING_FOR_REQUESTS
  8387. X    strcpy (match2, "\\2");
  8388. X    re_strcmp (REQUESTS, line, match2); /* Get list specified (if any) */
  8389. X    if (match2[0] == EOS)
  8390. X      request_found = TRUE; /* Request does not take 'list' arg */
  8391. X    else if (get_list_id (match2, &sys, nlists) >= 0)
  8392. X#endif
  8393. X      request_found = TRUE;
  8394. X      }
  8395. X      if (request_found < 0)
  8396. X    request_found = FALSE;
  8397. X    }
  8398. X    fgets (line, MAX_LINE - 2, mail);
  8399. X  }
  8400. X  fclose (msg);
  8401. X
  8402. X  strcpy (linecopy, line); /*** VERY IMPORTANT: we are now at the next msg ***/
  8403. X
  8404. X  if (!address_ok) {        /* Abort message */
  8405. X    NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS (sender, "process_message", TRUE);
  8406. X    return;
  8407. X  }
  8408. X
  8409. X  if (control_article) {
  8410. X    report_progress (report, "Control message ignored", TRUE);
  8411. X    return;
  8412. X  }
  8413. X  if (sender_subscribed != PEER &&
  8414. X      re_strcmp (LOW_PRECEDENCES, precedence, NULL) > 0) {
  8415. X    NOTIFY_OWNER_OF_MSG_IGNORED ("Low Precedence: %s message ignored.",
  8416. X                 precedence);
  8417. X    return;
  8418. X  }
  8419. X  /* Check the IGNORED file */
  8420. X  if (ignore_sender (ignored, sender, report, FALSE)) {
  8421. X    NOTIFY_OWNER_OF_MSG_IGNORED ("The sender's address (%s) matches entries\n\
  8422. Xin the list's .ignored file.", sender);
  8423. X    return;
  8424. X  }
  8425. X  if (originator[0] != EOS) /* Check for mail loop using Originator: */
  8426. X    if (ignore_sender (ignored, originator, report, FALSE)) {
  8427. X    NOTIFY_OWNER_OF_MSG_IGNORED ("The Originator: address (%s) matches \
  8428. Xentries\nin the list's .ignored file.", originator);
  8429. X      return;
  8430. X    }
  8431. X  if (reply_to[0] != EOS) /* Check for mail loop using Reply-To: */
  8432. X    if (ignore_sender (ignored, reply_to, report, FALSE)) {
  8433. X    NOTIFY_OWNER_OF_MSG_IGNORED ("The Reply-To: address (%s) matches entries\n\
  8434. Xin the list's .ignored file.", reply_to);
  8435. X      return;
  8436. X    }
  8437. X  if (message_id[0] != EOS) { /* Check for mail loop using Message-Id: */
  8438. X    strcpy (id_copy, message_id);
  8439. X    upcase (id_copy);
  8440. X    if (message_ids = fopen (message_idsf, "r")) {
  8441. X      if (ignore_sender (message_ids, id_copy, report, TRUE)) {
  8442. X        fclose (message_ids);
  8443. X    NOTIFY_OWNER_OF_MSG_IGNORED ("The Message-Id: %s matches entries\n\
  8444. Xin the list's .message.ids file.", id_copy);
  8445. X        return;
  8446. X      }
  8447. X      fclose (message_ids);
  8448. X    }
  8449. X  }
  8450. X  /* Check for mail loop using Message-Id: and X-Listprocessor-Version: in
  8451. X     the body */
  8452. X  mailer_daemon = strinstr (MAILER_DAEMON, sender) ||
  8453. X    (original_sender[0] != EOS && strinstr (MAILER_DAEMON, original_sender)) ||
  8454. X    *sender == EOS;
  8455. X  susp_subject = (senders_subject[0] != EOS &&
  8456. X          strinstr (SUSP_SUBJECT, senders_subject));
  8457. X
  8458. X  if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report) &&
  8459. X      !mailer_daemon && !susp_subject) {
  8460. X    OPEN_FILE (msg, msgf, "r", "process_message");
  8461. X    sumf = mystrdup (tmpnam (NULL));
  8462. X    while (!feof (msg)) {
  8463. X      RESET (line);
  8464. X      fgets (line, MAX_LINE - 2, msg);
  8465. X      if (re_strcmp (MESSAGE_ID1, line, NULL) > 0 ||
  8466. X      re_strcmp (MESSAGE_ID2, line, NULL) > 0 ||
  8467. X      re_strcmp (MESSAGE_ID3, line, NULL) > 0) {
  8468. X    strcpy (id_copy, line + strlen ("Message-") + 4);
  8469. X    id_copy [strlen (id_copy) - 1] = EOS; /* \n -> \0 */
  8470. X    upcase (id_copy);
  8471. X    if (message_ids = fopen (message_idsf, "r")) {
  8472. X      if (ignore_sender (message_ids, id_copy, report, TRUE)) {
  8473. X        fclose (msg);
  8474. X        fclose (message_ids);
  8475. X        NOTIFY_OWNER_OF_MSG_IGNORED ("A message with Message-Id: %s \
  8476. X(appearing\nin the body) matches entries in the list's .message.ids file.", 
  8477. X                         id_copy);
  8478. X        return;
  8479. X      }
  8480. X      fclose (message_ids);
  8481. X    }
  8482. X      }
  8483. X      else if (re_strcmp (LISTPROC_ID, line, NULL) > 0) {
  8484. X    fclose (msg);
  8485. X    NOTIFY_OWNER_OF_MSG_IGNORED ("Found X-Listprocessor-Version: id in \
  8486. Xmessage body; message ignored", "");
  8487. X    return;
  8488. X      }
  8489. X    }
  8490. X    fclose (msg);
  8491. X  }
  8492. X
  8493. X  if (!sumf)
  8494. X    sumf = mystrdup (tmpnam (NULL));
  8495. X  /* Check for mail loop by comparing checksums */
  8496. X  syscom ("tr -d ' \t\\012' < %s | sum | awk '{ print $1 }' > %s",
  8497. X      msgf, sumf);
  8498. X  OPEN_FILE (msg, sumf, "r", "process_message");
  8499. X  fscanf (msg, "%s", sum);
  8500. X  fclose (msg);
  8501. X  if (atoi (sum) == 0) {
  8502. X    NOTIFY_OWNER_OF_MSG_IGNORED ("This message has no body.", "");
  8503. X    return;
  8504. X  }
  8505. X  if (msg = fopen (checksumsf, "r")) {
  8506. X    if (ignore_sender (msg, sum, report, TRUE)) {
  8507. X      fclose (msg);
  8508. X      NOTIFY_OWNER_OF_MSG_IGNORED ("The body of the message has a checksum \
  8509. Xmatching those messages already\ndistributed.", "");
  8510. X      return;
  8511. X    }
  8512. X    fclose (msg);
  8513. X  }
  8514. X  unlink (sumf);
  8515. X  free ((char *) sumf);
  8516. X
  8517. X  if (sender_subscribed == NEWS)
  8518. X    if (ignore_sender (peers, originator, report, TRUE)) {
  8519. X      NOTIFY_OWNER_OF_MSG_IGNORED ("The Originator: address (%s) in the \
  8520. Xarticle\nmatches entries in the list's .ignored file.", originator);
  8521. X      return;
  8522. X    }
  8523. X
  8524. X  if (originator[0] == EOS) /* Fresh message originating from this list */
  8525. X    sprintf (originator, "%s", sys.lists[listid].address);
  8526. X  upcase (originator);
  8527. X
  8528. X  if (do_not_check_subscriptions && sender_subscribed == NOTSUBSCRIBED)
  8529. X    sender_subscribed = SUBSCRIBED;
  8530. X  if (sender_subscribed == NOTSUBSCRIBED || mailer_daemon || susp_subject ||
  8531. X      request_found > 0) {
  8532. X    /* Send error message to sender */
  8533. X    report_progress (report,
  8534. X             tsprintf ("Invalid message #%04d (%s). Forwarding error \
  8535. Xmessage to %s.\n%s",
  8536. X                   ++returned_msg,
  8537. X                   (mailer_daemon ? "suspicious address" :
  8538. X                (susp_subject ? "suspicious subject" :
  8539. X                 (request_found > 0 ? "request sensed" : 
  8540. X                  (sender_subscribed == NOTSUBSCRIBED ?
  8541. X                   "sender not subscribed" :
  8542. X                   "???")))),
  8543. X                   ((mailer_daemon || susp_subject || errors_to_owner) ?
  8544. X                sys.lists[listid].owner : sender),
  8545. X                   (*sender != EOS ? sender : "\"\"")), TRUE);
  8546. X    OPEN_FILE (msg_no, msg_nof, "w", "process_message");
  8547. X    fprintf (msg_no, "%d %d\n", public_msg, returned_msg);
  8548. X    fclose (msg_no);
  8549. X    OPEN_FILE (msg, msgf, "r", "process_message");
  8550. X    /* Prepare header */
  8551. X    create_header (&forwardmail, mailforwardf, sys.lists[listid].address,
  8552. X      originator,
  8553. X      ((mailer_daemon || susp_subject || errors_to_owner) ?
  8554. X       sys.lists[listid].owner : sender),
  8555. X      senders_subject, COPY_OWNER (ccerrors), FALSE, TRUE);
  8556. X    if (errors_to_owner || mailer_daemon || susp_subject)
  8557. X      fprintf (forwardmail, "\nRejected message: sent to %s by %s \
  8558. Xfollows.\nReason for rejection: %s.\n",
  8559. X           sys.lists[listid].address, (*sender != EOS ? sender : "\"\""),
  8560. X           (mailer_daemon ? "suspicious address" :
  8561. X        (susp_subject ? "suspicious subject" :
  8562. X         (request_found > 0 ? "request sensed" : 
  8563. X          (sender_subscribed == NOTSUBSCRIBED ? "sender not subscribed" :
  8564. X           "???")))));
  8565. X    else if (request_found > 0)
  8566. X      if (sender_subscribed != PEER && sender_subscribed != NEWS)
  8567. X    /* First line of msg contained a request; send it back w/ apologies */
  8568. X    fprintf (forwardmail, "\nWe are sorry, but this system sensed the \
  8569. Xfollowing request which may have been\ninadvertedly sent to this list:\n\n%s\n\
  8570. X\nIf your posting was intentional, please accept our apologies and resend your\
  8571. X\nmail message, making sure you do not include anything that may look like a\
  8572. X\nrequest in the first line of the body of the actual message. If this was \
  8573. X\nindeed a request please resend it to %s\nYour entire message\nis copied \
  8574. Xbelow.\n\n", match, sys.server.address);
  8575. X      else
  8576. X    report_progress (report, "Message from peer/news ignored: request \
  8577. Xsensed\n", FALSE);
  8578. X    else {
  8579. X      fprintf (forwardmail, "%s: You are not subscribed to %s.\n\
  8580. XYour message is returned to you unprocessed. If you want to subscribe,\n\
  8581. Xsend mail to %s with the following request:\n\n\t\tsubscribe %s Your Name\n\n",               sender, sys.lists[listid].address, sys.server.address,
  8582. X               sys.lists[listid].alias);
  8583. X      if (alternate_addresses) {
  8584. X    fprintf (forwardmail, "In addition, the system found the following \
  8585. Xaddress(es) that resemble yours.\nIf one of these is you, please resend your \
  8586. Xmessage from that one, or use the\n'set <list> address' request to change the \
  8587. Xaddress you are subscribed with:\n\n");
  8588. X    for (i = 0; alternate_addresses[i]; ++i)
  8589. X      fprintf (forwardmail, "%s\n", alternate_addresses[i]),
  8590. X      free ((char *) alternate_addresses[i]);
  8591. X    free ((char **) alternate_addresses);
  8592. X    alternate_addresses = NULL;
  8593. X    fprintf (forwardmail, "\n");
  8594. X      }
  8595. X    }
  8596. X
  8597. X#ifdef ERROR_MAIL_ANALYSIS
  8598. X    if (mailer_daemon) { /* See if we should remove the user and/or log error */
  8599. X      char line [1024], matches [MAX_LINE], matches2 [MAX_LINE],
  8600. X        subj [MAX_LINE];
  8601. X      BOOLEAN fatal_subject;
  8602. X
  8603. X      RESET (line);
  8604. X      rewind (msg);
  8605. X      strcpy (subj, subject_copy);
  8606. X      upcase (subj);
  8607. X      while (!feof (msg) &&
  8608. X         !_strstr (line, "UNSENT MESSAGE FOLLOWS") &&
  8609. X         !_strstr (line, "REJECTED MESSAGE") &&
  8610. X         !_strstr (line, "TRANSCRIPT OF MESSAGE FOLLOWS") &&
  8611. X         !_strstr (line, "RETURNED MAIL") &&
  8612. X         re_strcmp ("^RECEIVED:[ \t]", line, NULL) <= 0 &&
  8613. X         re_strcmp ("^REPLY-TO:[ \t]", line, NULL) <= 0 &&
  8614. X         re_strcmp ("^SENDER:[ \t]", line, NULL) <= 0 &&
  8615. X         re_strcmp ("^DATE:[ \t]", line, NULL) <= 0 &&
  8616. X         re_strcmp ("^TO:[ \t]", line, NULL) <= 0) {
  8617. X    fgets (line, 1023, msg);
  8618. X    upcase (line);
  8619. X    strcpy (matches, "\\1.*\\2");
  8620. X    strcpy (matches2, "\\1");
  8621. X    if (re_strcmp (errors, line, matches) > 0 ||
  8622. X        ((fatal_subject = re_strcmp (fatal_subjects, subj, matches2)) > 0 &&
  8623. X         ((atoi (matches2) >= (GRACE_PERIOD / 86400)) ||
  8624. X          matches2[0] == EOS))) {
  8625. X      /* Remove user if present */
  8626. X      char address [MAX_LINE], address_copy [MAX_LINE],_line [1024],
  8627. X        _address [MAX_LINE];
  8628. X
  8629. X# if (ERROR_MAIL_ANALYSIS == 9)
  8630. X      if (fatal_subject > 0) {
  8631. X        strcpy (matches, ".*\\1"); /* See if warning and get host name */
  8632. X        re_strcmp (warnings, line, matches);
  8633. X        if (re_strcmp ("^\\.\\*[a-zA-Z0-9_-]+\\.[a-zA-Z0-9.:_-]+$", matches, NULL) <= 0)
  8634. X          strcpy (matches, ".*\\1"); /* Hostname syntax failed */
  8635. X      }
  8636. X      if (matches [0] != EOS && matches [strlen (matches) - 1] == '\n')
  8637. X        matches [strlen (matches) - 1] = EOS;
  8638. X# endif
  8639. X      if (re_strcmp ("\\[|\\]", matches, NULL) > 0) /* Trojan */
  8640. X        strcpy (matches, "\\1.*\\2");
  8641. X      if (re_strcmp ("\\[|\\]", matches2, NULL) > 0) /* Trojan */
  8642. X        strcpy (matches2, "\\1");
  8643. X      rewind (subscribers);
  8644. X      while (!feof (subscribers)) {
  8645. X        address [0] = RESET (_line);
  8646. X        fgets (_line, 1023, subscribers);
  8647. X        sscanf (_line, "%s", address);
  8648. X        upcase (_line);
  8649. X        upcase (address);
  8650. X        strcpy (address_copy, address);
  8651. X        escape_re (address);
  8652. X        if (strcmp (matches, ".*") &&
  8653. X# if (ERROR_MAIL_ANALYSIS == 9)
  8654. X        strcmp (matches, ".*\\1") &&
  8655. X# endif
  8656. X        strcmp (matches, "\\1.*\\2"))
  8657. X          sprintf (_address, "^[ \t]*%s", matches +
  8658. X               (!strncmp (matches, ".*", 2) ? 2 : 0));
  8659. X        else
  8660. X          strcpy (_address, address),
  8661. X          strcpy (_line, line);
  8662. X        if (address [0] != EOS && re_strcmp (_address, _line, NULL) > 0) {
  8663. X          /* User found; remove him */
  8664. X          char _address [MAX_LINE];
  8665. X          BOOLEAN removed = FALSE;
  8666. X
  8667. X          fclose (subscribers);
  8668. X          sprintf (_address, "^[\t ]*%s ", address);
  8669. X          if (cp (subscribersf, OLD_SUBSCRIBERS))
  8670. X        gexit (16);
  8671. X          REMOVE_ADDRESS (_address, OLD_SUBSCRIBERS, NEW_SUBSCRIBERS,
  8672. X                  removed_usersf);
  8673. X# ifdef bsd
  8674. X          sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  8675. X# elif defined (svr4) || defined (svr3)
  8676. X          sighold (SIGINT);
  8677. X          sighold (SIGTERM);
  8678. X# endif
  8679. X          if (mv (NEW_SUBSCRIBERS, subscribersf))
  8680. X        gexit (16);
  8681. X# ifdef bsd
  8682. X          sigsetmask (sig_mask);
  8683. X# elif defined (svr4) || defined (svr3)
  8684. X          sigrelse (SIGINT);
  8685. X          sigrelse (SIGTERM);
  8686. X# endif
  8687. X          OPEN_FILE (subscribers, subscribersf, "r", "process_message");
  8688. X          if (cp (aliasesf, OLD_ALIASES))
  8689. X        gexit (16);
  8690. X          REMOVE_ADDRESS (_address, OLD_ALIASES, NEW_ALIASES,
  8691. X                  removed_aliasesf);
  8692. X# ifdef bsd
  8693. X          sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  8694. X# elif defined (svr4) || defined (svr3)
  8695. X          sighold (SIGINT);
  8696. X          sighold (SIGTERM);
  8697. X# endif
  8698. X          if (mv (NEW_ALIASES, aliasesf))
  8699. X        gexit (16);
  8700. X# ifdef bsd
  8701. X          sigsetmask (sig_mask);
  8702. X# elif defined (svr4) || defined (svr3)
  8703. X          sigrelse (SIGINT);
  8704. X          sigrelse (SIGTERM);
  8705. X# endif
  8706. X          if (cp (ALIASESF, OLD_ALIASES))
  8707. X        gexit (16);
  8708. X          REMOVE_ADDRESS (_address, OLD_ALIASES, NEW_ALIASES, "/dev/null");
  8709. X# ifdef bsd
  8710. X          sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  8711. X# elif defined (svr4) || defined (svr3)
  8712. X          sighold (SIGINT);
  8713. X          sighold (SIGTERM);
  8714. X# endif
  8715. X          if (mv (NEW_ALIASES, ALIASESF))
  8716. X        gexit (16);
  8717. X# ifdef bsd
  8718. X          sigsetmask (sig_mask);
  8719. X# elif defined (svr4) || defined (svr3)
  8720. X          sigrelse (SIGINT);
  8721. X          sigrelse (SIGTERM);
  8722. X# endif
  8723. X          sprintf (_address, " %s[\t ]*$", address);
  8724. X          if (cp (aliasesf, OLD_ALIASES))
  8725. X        gexit (16);
  8726. X          REMOVE_ADDRESS (_address, OLD_ALIASES, NEW_ALIASES, 
  8727. X                  removed_aliasesf);
  8728. X# ifdef bsd
  8729. X          sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  8730. X# elif defined (svr4) || defined (svr3)
  8731. X          sighold (SIGINT);
  8732. X          sighold (SIGTERM);
  8733. X# endif
  8734. X          if (mv (NEW_ALIASES, aliasesf))
  8735. X        gexit (16);
  8736. X# ifdef bsd
  8737. X          sigsetmask (sig_mask);
  8738. X# elif defined (svr4) || defined (svr3)
  8739. X          sigrelse (SIGINT);
  8740. X          sigrelse (SIGTERM);
  8741. X# endif
  8742. X          if (cp (ALIASESF, OLD_ALIASES))
  8743. X        gexit (16);
  8744. X          REMOVE_ADDRESS (_address, OLD_ALIASES, NEW_ALIASES, "/dev/null");
  8745. X# ifdef bsd
  8746. X          sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  8747. X# elif defined (svr4) || defined (svr3)
  8748. X          sighold (SIGINT);
  8749. X          sighold (SIGTERM);
  8750. X# endif
  8751. X          if (mv (NEW_ALIASES, ALIASESF))
  8752. X        gexit (16);
  8753. X# ifdef bsd
  8754. X          sigsetmask (sig_mask);
  8755. X# elif defined (svr4) || defined (svr3)
  8756. X          sigrelse (SIGINT);
  8757. X          sigrelse (SIGTERM);
  8758. X# endif
  8759. X          unlink (OLD_SUBSCRIBERS);
  8760. X          unlink (OLD_ALIASES);
  8761. X          if (removed)
  8762. X        fprintf (forwardmail, "Automatic removal: user %s\n\
  8763. X  (possibly mentioned below) will be removed from the system files.\n", address);
  8764. X          else {
  8765. X        fprintf (forwardmail, "Automatic removal of user %s\n  failed.\n",
  8766. X             address_copy);
  8767. X        break;
  8768. X          }
  8769. X        }
  8770. X      }
  8771. X    } 
  8772. X
  8773. X    strcpy (matches, ".*\\1");
  8774. X    if (re_strcmp (warnings, line, matches) > 0) {
  8775. X      FILE *inerrors, *outerrors;
  8776. X      BOOLEAN found = FALSE;
  8777. X      char _line [1024], address [MAX_LINE], _address [MAX_LINE], *sp;
  8778. X      long int stime;
  8779. X
  8780. X      mv (errorsf, errors2f);
  8781. X      inerrors = fopen (errors2f, "r");
  8782. X      OPEN_FILE (outerrors, errorsf, "w", "process_message");
  8783. X      while (inerrors && !feof (inerrors)) {
  8784. X        RESET (_line);
  8785. X        fgets (_line, 1023, inerrors);
  8786. X        sscanf (_line, "%ld", &stime);
  8787. X        if ((sp = strchr (_line, ' ')))
  8788. X          ++sp;
  8789. X        else
  8790. X          sp = _line;
  8791. X        upcase (sp);
  8792. X        if (!strcmp (line, sp)) { /* Match */
  8793. X          found = TRUE;
  8794. X          if ((long int) time (0) < (long int) (stime + GRACE_PERIOD))
  8795. X        /* No action */
  8796. X        fputs (_line, outerrors);
  8797. X          else {    /* Look for matches in the subscribers file and */
  8798. X        char mode [MAX_LINE], address_copy [MAX_LINE], *p;
  8799. X
  8800. X        rewind (subscribers); /* change mail mode to POSTPONE */
  8801. X        while (!feof (subscribers)) {
  8802. X          mode [0] = address [0] = RESET (_line);
  8803. X          fgets (_line, 1023, subscribers);
  8804. X          sscanf (_line, "%s %s", address, mode);
  8805. X          if (!strcmp (mode, POSTPONE))
  8806. X            continue;
  8807. X          upcase (_line);
  8808. X          upcase (address);
  8809. X          strcpy (address_copy, address);
  8810. X          escape_re (address);
  8811. X# if (ERROR_MAIL_ANALYSIS == 9)
  8812. X          if (strcmp (matches, ".*") && strcmp (matches, ".*\\1"))
  8813. X            sprintf (_address, "^[ \t]*%s", matches + 2);
  8814. X          else
  8815. X# endif
  8816. X            strcpy (_address, address),
  8817. X            strcpy (_line, line);
  8818. X          if (p = strchr (_address, '<'))
  8819. X            sprintf (p, "%s", p + 1); /* Remove '<' */
  8820. X          if (p = strchr (_address, '>'))
  8821. X            sprintf (p, "%s", p + 1);  /* Remove '>' */
  8822. X          if (address [0] != EOS && re_strcmp (_address, _line, NULL) >
  8823. X              0) {
  8824. X            /* User found; change mode */
  8825. X            char _address [MAX_LINE];
  8826. X            BOOLEAN suspended = FALSE;
  8827. X
  8828. X            fclose (subscribers);
  8829. X            sprintf (_address, "^[\t ]*%s ", address);
  8830. X            if (cp (subscribersf, OLD_SUBSCRIBERS))
  8831. X              gexit (16);
  8832. X            SUSPEND_ADDRESS (_address, OLD_SUBSCRIBERS, NEW_SUBSCRIBERS);
  8833. X# ifdef bsd
  8834. X            sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  8835. X# elif defined (svr4) || defined (svr3)
  8836. X            sighold (SIGINT);
  8837. X            sighold (SIGTERM);
  8838. X# endif
  8839. X            if (mv (NEW_SUBSCRIBERS, subscribersf))
  8840. X              gexit (16);
  8841. X# ifdef bsd
  8842. X            sigsetmask (sig_mask);
  8843. X# elif defined (svr4) || defined (svr3)
  8844. X            sigrelse (SIGINT);
  8845. X            sigrelse (SIGTERM);
  8846. X# endif
  8847. X            OPEN_FILE (subscribers, subscribersf, "r", "process_message");
  8848. X            if (suspended)
  8849. X              fprintf (forwardmail, "Subscription subspension: user \
  8850. X%s\n  (possibly mentioned below) will have his mail mode reset to POSTPONE.\n",
  8851. X                   address_copy);
  8852. X            else {
  8853. X              fprintf (forwardmail, "Attempt to suspend subscription \
  8854. Xof user %s\n  failed.\n", address_copy);
  8855. X              break;
  8856. X            }
  8857. X          }
  8858. X        }
  8859. X              }
  8860. X        }
  8861. X        else if ((long int) time (0) < (long int) (stime + ONE_MONTH))
  8862. X          /* discard if older > 1 mo */
  8863. X          fputs (_line, outerrors); /* No match; copy error line as is */
  8864. X      }
  8865. X      if (!found)    /* Save new error message */
  8866. X        fprintf (outerrors, "%ld %s", time (0), line),
  8867. X        fprintf (forwardmail, "Recorded new error message: %s", line);
  8868. X      fclose (outerrors);
  8869. X      if (inerrors)
  8870. X        fclose (inerrors);
  8871. X      unlink (errors2f);
  8872. X    }
  8873. X      }
  8874. X    }
  8875. X#endif
  8876. X
  8877. X    fprintf (forwardmail, "-----------------------------------------------\
  8878. X--------------------------------\n");
  8879. X    rewind (msg);
  8880. X    while (!feof (msg))  /* Copy actual message */
  8881. X      RESET (line),
  8882. X      fgets (line, MAX_LINE - 2, msg),
  8883. X      fprintf (forwardmail, "%s", line);
  8884. X    COMPLETE_TELNET (forwardmail);
  8885. X    fclose (forwardmail);
  8886. X    fclose (msg);
  8887. X    /* Form  sendmail command */
  8888. X    if (sender_subscribed != PEER && sender_subscribed != NEWS)
  8889. X      if (sys.options & USE_SYSMAIL)
  8890. X    sysmail (mailforwardf);
  8891. X      else
  8892. X    syscom ("%s '%s' < %s", sys.mail.method,
  8893. X        (((sys.options & USE_TELNET) == 0) ?
  8894. X         ((mailer_daemon || susp_subject || errors_to_owner) ?
  8895. X          sys.lists[listid].owner : locase (sender)) : ""),
  8896. X        mailforwardf);
  8897. X    return;
  8898. X  }
  8899. X  if (is_moderated) /* USER CONTRIBUTED CODE: Warren Burstein */
  8900. X    if (owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
  8901. X      /* 
  8902. X     Sender is owner, look for MESSAGE SEPARATOR, subject and sender,
  8903. X     and blank lines and set lines_to_skip (# of lines till 
  8904. X     MESSAGE_SEPARATOR + one for Subject: + one for Sender: + blank lines)
  8905. X      */
  8906. X      FILE *msg;
  8907. X      long int line_no = 0;
  8908. X
  8909. X      OPEN_FILE (msg, msgf, "r", "process_message");
  8910. X      while (!feof (msg)) {
  8911. X    RESET (line);
  8912. X    fgets (line, MAX_LINE - 2, msg);
  8913. X    if (line [0] != EOS && line [strlen (line) - 1] == '\n')
  8914. X      line [strlen (line) - 1] = EOS;
  8915. X    line_no++;
  8916. X
  8917. X    if (!strcmp (line, MESSAGE_SEPARATOR)) {
  8918. X      lines_to_skip = line_no;
  8919. X      break;
  8920. X    }
  8921. X      }
  8922. X
  8923. X      if (lines_to_skip) {
  8924. X    /* Look for Subject: and Sender:, skip blank lines */
  8925. X    char match [MAX_LINE];
  8926. X    while (!feof (msg)) {
  8927. X      RESET (line);
  8928. X      fgets (line, MAX_LINE - 2, msg);
  8929. X      if (line [0] != EOS && line [strlen (line) - 1] == '\n')
  8930. X        line [strlen (line) - 1] = EOS;
  8931. X
  8932. X      strcpy (match, "\\1");
  8933. X      if (re_strcmp (SUBJECT, line, match) > 0)
  8934. X        strcpy (senders_subject, line + strlen (match)),
  8935. X        strcpy (subject_copy, senders_subject),
  8936. X        lines_to_skip++;
  8937. X      else if (re_strcmp (SENDER, line, match) > 0)
  8938. X        strcpy (original_sender, line + strlen (match)),
  8939. X        lines_to_skip++;
  8940. X      else if (line[0] == EOS) {
  8941. X        lines_to_skip++;    /* [Tasos: ???] */
  8942. X        break;
  8943. X      }
  8944. X      else
  8945. X        break;
  8946. X        }
  8947. X        while (!feof (msg)) {
  8948. X      RESET (line);
  8949. X      fgets (line, MAX_LINE - 2, msg);
  8950. X      if (strcmp (line, "\n"))
  8951. X        break;
  8952. X      lines_to_skip++;
  8953. X        }
  8954. X      }
  8955. X
  8956. X      fclose (msg);
  8957. X    }
  8958. X    else { /* Sender isn't owner, send message to owner */
  8959. X      int i;
  8960. X
  8961. X      report_progress (report, tsprintf ("Public message #%04d. Forwarding to \
  8962. Xmoderator", ++public_msg), TRUE);
  8963. X      OPEN_FILE (msg_no, msg_nof, "w", "process_message");
  8964. X      fprintf (msg_no, "%d %d\n", public_msg, returned_msg);
  8965. X      fclose (msg_no);
  8966. X
  8967. X      create_header (&forwardmail, mailforwardf, original_sender,
  8968. X             originator, sys.lists[listid].owner, senders_subject,
  8969. X             FALSE, TRUE, FALSE);
  8970. X
  8971. X      sprintf (line, "This message was submitted by %s to list %s.",
  8972. X           original_sender, sys.lists[listid].address);
  8973. X      fill_text (forwardmail, line);
  8974. X      for (i = 0; msgs[i]; i++)
  8975. X    fill_text (forwardmail, msgs[i]);
  8976. X      fprintf (forwardmail, "%s\n", MESSAGE_SEPARATOR);
  8977. X
  8978. X      /* Send these two under the line for extraction when the moderator
  8979. X     forwards the message back */
  8980. X      fprintf (forwardmail, "Sender: %s\nSubject: %s\n\n",
  8981. X           original_sender, senders_subject);
  8982. X      if (copy_msg (forwardmail, msgf, FALSE, original_sender, 0, TRUE, FALSE))
  8983. X        sendmail (sys.lists[listid].owner, FALSE, FALSE, 0, 0, mailforwardf);
  8984. X      already_sent = message_forwarded = TRUE;
  8985. X    }
  8986. X  fclose (msg);
  8987. X  
  8988. X  if (!already_sent) {
  8989. X    report_progress (report,
  8990. X             tsprintf ("Public message #%04d%s. Distributing to all \
  8991. Xsubscribers%s.\n%s",
  8992. X                   ++public_msg,
  8993. X                   (sender_subscribed == NEWS ? " (news)" : 
  8994. X                (sender_subscribed == PEER ? " (peer)" : "")), 
  8995. X                   (sender_subscribed == SUBSCRIBED ? 
  8996. X                ", news groups and peers" : 
  8997. X                (sender_subscribed == NEWS ? ", peers" : 
  8998. X                 ", news groups")),
  8999. X                   sender), TRUE);
  9000. X    if (fake_mail && at)
  9001. X      report_progress (report,
  9002. X               tsprintf ("*** Possible fake mail: Host %s in user \
  9003. Xaddress does\nnot match any of the domains in the Received: header lines.\n",
  9004. X                 at + 1), FALSE);
  9005. X    OPEN_FILE (msg_no, msg_nof, "w", "process_message");
  9006. X    fprintf (msg_no, "%d %d\n", public_msg, returned_msg);
  9007. X    fclose (msg_no);
  9008. X    distributions (sender_subscribed, headerf, msgf, FALSE, sender,
  9009. X           original_sender, senders_subject, subject_copy, originator,
  9010. X           lines_to_skip, is_moderated);
  9011. X
  9012. X    if (append_to_digest && !message_rejected) {
  9013. X      long int line_no = 0, digest_toc_lines, digest_lines, total;
  9014. X      FILE *fp, *msg;
  9015. X
  9016. X      OPEN_FILE (fp, digest_tocf, "a", "process_message");
  9017. X      fprintf (fp, "%s\n%s\n", senders_subject, original_sender);
  9018. X      fclose (fp);
  9019. X
  9020. X      OPEN_FILE (fp, digest_msgf, "a", "process_message");
  9021. X      fprintf (fp, "\n");
  9022. X      if (sent_date[0] != EOS)
  9023. X    fprintf (fp, "Date: %s\n", sent_date);
  9024. X      if (original_sender[0] != EOS)
  9025. X    fprintf (fp, "From: %s\n", original_sender);
  9026. X      if (recipients[0] != EOS)
  9027. X    fprintf (fp, "To: %s\n", recipients);
  9028. X      if (ccrecipients[0] != EOS)
  9029. X    fprintf (fp, "Cc: %s\n", ccrecipients);
  9030. X      if (senders_subject[0] != EOS)
  9031. X    fprintf (fp, "Subject: %s\n", senders_subject);
  9032. X      if (message_id[0] != EOS)
  9033. X    fprintf (fp, "Message-ID: %s\n", message_id);
  9034. X      if (keywords[0] != EOS)
  9035. X    fprintf (fp, "Keywords: %s\n", keywords);
  9036. X      fprintf (fp, "\n");
  9037. X
  9038. X      OPEN_FILE (msg, msgf, "r", "process_message");
  9039. X      while (!feof (msg)) { /* Copy actual message */
  9040. X    RESET (line);
  9041. X    fgets (line, MAX_LINE - 2, msg);
  9042. X    line_no++;
  9043. X
  9044. X    if (line_no > lines_to_skip)
  9045. X      fprintf (fp, "%s", line);
  9046. X      }
  9047. X      fclose(msg);
  9048. X
  9049. X      fprintf (fp, "\n------------------------------\n");
  9050. X      fclose(fp);
  9051. X
  9052. X      digest_toc_lines = count_lines_in_file (fp = fopen (digest_tocf, "r"));
  9053. X      if (fp) fclose(fp);
  9054. X      digest_lines = count_lines_in_file (fp = fopen (digest_msgf, "r"));
  9055. X      if (fp) fclose(fp);
  9056. X
  9057. X      report_progress (report, tsprintf ("Adding to digest, which now has \
  9058. X%d token + %d message = %d lines",
  9059. X               digest_toc_lines, digest_lines,
  9060. X               (total = digest_toc_lines + digest_lines)), TRUE);
  9061. X
  9062. X      if (total >= sys.lists[listid].digest_lines) { /* Max lines exceeded */
  9063. X    BOOLEAN fd = force_digest;
  9064. X
  9065. X    force_digest = TRUE;
  9066. X        digest_make (TRUE);
  9067. X        digest_distribute ();
  9068. X    force_digest = fd;
  9069. X      }
  9070. X    }
  9071. X  }
  9072. X
  9073. X  update_unprocessed_messages (unprocessed_messages);
  9074. X  unlink (unprocessed_tmp);
  9075. X
  9076. X  if (!message_rejected && !message_forwarded) { /* New message is archived */
  9077. X    cat_append (headerf, archivef);
  9078. X    OPEN_FILE (in, msgf, "r", "process_message");
  9079. X    OPEN_FILE (out, archivef, "a", "process_message");
  9080. X    if (is_moderated) { /* Skip message lines before appending */
  9081. X      long int offset = ftell (in); /* Store current position */
  9082. X      while (!feof (in)) {
  9083. X    RESET (line);
  9084. X    fgets (line, MAX_LINE - 2, in);
  9085. X    if (line [0] != EOS && line [strlen (line) - 1] == '\n')
  9086. X      line [strlen (line) - 1] = EOS;
  9087. X    if (!strcmp (line, MESSAGE_SEPARATOR))
  9088. X      break;
  9089. X      }
  9090. X      if (feof (in))    /* No message separator, so archive the whole msg */
  9091. X    (void) fseek (in, offset, SEEK_SET);
  9092. X    }
  9093. X    while (!feof (in))
  9094. X      RESET (line),
  9095. X      fgets (line, MAX_LINE - 2, in),
  9096. X      fputs (line, out);
  9097. X    fclose (in);
  9098. X    fclose (out);
  9099. X    unlink (headerf);
  9100. X    if (is_moderated) /* Save the original author's address */
  9101. X      extract_address (original_sender),
  9102. X      upcase (original_sender),
  9103. X      fprintf (headers, "%s\n", original_sender);
  9104. X    else
  9105. X      fprintf (headers, "%s\n", sender);
  9106. X    fflush (headers);
  9107. X  }
  9108. X
  9109. X  if (message_id[0] != EOS && !message_rejected && !message_forwarded) {
  9110. X    if ((message_ids = fopen (message_idsf, "a")) == NULL)
  9111. X      report_progress (report,
  9112. X               tsprintf ("\nprocess_message(): Could not open %s",
  9113. X                 message_idsf), TRUE),
  9114. X      gexit (1);
  9115. X    fprintf (message_ids, "%s %s\n", message_id, sender); /* Save new id */
  9116. X    fclose (message_ids);
  9117. X  }
  9118. X  if (sum[0] != EOS && !message_rejected && !message_forwarded)
  9119. X    if ((message_ids = fopen (checksumsf, "a")))
  9120. X      fprintf (message_ids, "%s %s\n", sum, sender),
  9121. X      fclose (message_ids);
  9122. X}
  9123. X
  9124. X/*
  9125. X  Check to see if there are subscribers/newsgroups/peers that did not
  9126. X  receive any mail because of a previous interrupted distribution.
  9127. X*/
  9128. X
  9129. XBOOLEAN unprocessed_users (char *unprocessed, char *s, FILE *report)
  9130. X{
  9131. X  struct stat stat_buf;
  9132. X
  9133. X  if (!stat (unprocessed, &stat_buf)) { /* There is undelivered mail */
  9134. X    if (stat_buf.st_size > 0)
  9135. X      report_progress (report,
  9136. X               tsprintf ("Resuming delivery of interrupted mail to %s",
  9137. X                 s), TRUE);
  9138. X    return TRUE;
  9139. X  }
  9140. X  return FALSE;
  9141. X}
  9142. X
  9143. X/*
  9144. X  Distribute a message, either to regular subscribers, or to DIGEST
  9145. X  subscribers if is_digest is TRUE.
  9146. X  Write an archive file if is_digest == sys.lists[listid].options & ARCHIVE_DIGEST
  9147. X*/
  9148. X
  9149. Xvoid distributions (BOOLEAN subscribed, char *header_file,
  9150. X            char *message_file, BOOLEAN is_digest,
  9151. X            char *sender, char *original_sender, char *senders_subject,
  9152. X            char *subject_copy, char *originator,
  9153. X            long int lines_to_skip, BOOLEAN is_moderated)
  9154. X{
  9155. X  BOOLEAN sremnants, nremnants, premnants, success;
  9156. X
  9157. X  if (!(sremnants = unprocessed_users (unprocessed_subscribersf,
  9158. X                       "subscribers", report)))
  9159. X    echo ("0", unprocessed_subscribersf);
  9160. X  if (!(nremnants = unprocessed_users (unprocessed_newsf, "news", report)))
  9161. X    echo ("0", unprocessed_newsf);
  9162. X  if (!(premnants = unprocessed_users (unprocessed_peersf, "peers", report)))
  9163. X    echo ("0", unprocessed_peersf);
  9164. X
  9165. X  success = do_distribute (message_file, subscribers, subscribersf, sremnants,
  9166. X               unprocessed_subscribersf, send_to_subscribers,
  9167. X               sender, original_sender, senders_subject,
  9168. X               subject_copy, originator, report, FALSE,
  9169. X               multi_recip, lines_to_skip, is_digest, TRUE,
  9170. X               subscribed, !is_digest);
  9171. X  unlink (unprocessed_subscribersf);
  9172. X
  9173. X  if ((subscribed == SUBSCRIBED || subscribed == PEER) && !is_digest && success)
  9174. X    /* Send to news also */
  9175. X    success &= do_distribute (message_file, news, newsf, nremnants,
  9176. X                  unprocessed_newsf, TRUE, sender, original_sender,
  9177. X                  senders_subject, subject_copy, originator, report,
  9178. X                  TRUE, FALSE, lines_to_skip, is_digest, FALSE,
  9179. X                  subscribed, FALSE);
  9180. X  unlink (unprocessed_newsf);
  9181. X
  9182. X  if ((subscribed == SUBSCRIBED || subscribed == NEWS) && !is_digest && success)
  9183. X    /* Send to peers also */
  9184. X    success &= do_distribute (message_file, peers, peersf, premnants,
  9185. X                  unprocessed_peersf, TRUE, sender, original_sender,
  9186. X                  senders_subject, subject_copy, originator, 
  9187. X                  report, FALSE, FALSE, lines_to_skip, is_digest,
  9188. X                  FALSE, subscribed, FALSE);
  9189. X  unlink (unprocessed_peersf);
  9190. X
  9191. X  if (success &&
  9192. X      (((sys.lists[listid].options & ARCHIVE_LIST) &&
  9193. X    !(sys.lists[listid].options & ARCHIVE_DIGEST) && !is_digest) ||
  9194. X       (is_digest & sys.lists[listid].options & ARCHIVE_DIGEST))) {
  9195. X#ifdef GO_INTERACTIVE
  9196. X    IN_CRITICAL_SECTION ("distributions", SEM_ARCHIVES);
  9197. X#endif
  9198. X    do_archive (header_file, message_file, subject_copy, is_moderated);
  9199. X#ifdef GO_INTERACTIVE
  9200. X    OUT_OF_CRITICAL_SECTION ("distributions", SEM_ARCHIVES);
  9201. X#endif
  9202. X  }
  9203. X}
  9204. X
  9205. X/*
  9206. X  Do the distribution of the message to the specified list of subscribers.
  9207. X  The BOOLEAN argument 'posting' should be TRUE when posting AND gating to
  9208. X  news, and FALSE otherwise.
  9209. X
  9210. X  Undelivered mail has higher priority.
  9211. X*/
  9212. X
  9213. XBOOLEAN do_distribute (char *message_file,
  9214. X               FILE *recipient_list, char *file, BOOLEAN mail_remnants,
  9215. X               char *unprocessed, BOOLEAN send_to_subscribers, 
  9216. X               char *sender, char *original_sender, char *senders_subject,
  9217. X               char *subject_copy, char *originator, FILE *report,
  9218. X               BOOLEAN posting, BOOLEAN multi_recip,
  9219. X               long int lines_to_skip, BOOLEAN is_digest,
  9220. X               BOOLEAN is_subscribers, BOOLEAN subscribed,
  9221. X               BOOLEAN check_size)
  9222. X{
  9223. X  char name [MAX_LINE];            /* holds each subscribers name */
  9224. X  char mailmode [MAX_LINE];        /* send message back to sender or not */
  9225. X  char subscriber [MAX_LINE];      /* holds each subscriber's address */
  9226. X  char recipient_file [MAX_LINE];  /* file of subscribers to use when -r */
  9227. X  char restricted_subscriber [MAX_LINE]; /* name of subscriber in RESTRICTED */
  9228. X  char line [MAX_LINE];
  9229. X  FILE *forwardmail, *f;
  9230. X  BOOLEAN alternate_file = FALSE;
  9231. X  int  nrecipients = 0, offset = -1;
  9232. X
  9233. X  /* Check if there is previously undelivered mail */
  9234. X  if (mail_remnants) { /* There is undelivered mail; move to offset */
  9235. X    OPEN_FILE (f, unprocessed, "r", "do_distribute");
  9236. X    fscanf (f, "%d", &offset);
  9237. X    fclose (f);
  9238. X    if (offset < 0) /* Empty unprocessed file, go to eof */
  9239. X      while (!feof (recipient_list))
  9240. X    fgets (line, MAX_LINE - 2, recipient_list);
  9241. X    else /* Skip 'offset' subscribers, check for DIGEST subscribers */
  9242. X      while (!feof (recipient_list) && offset) {
  9243. X    if (!is_digest &&
  9244. X        read_recipient (recipient_list, subscriber, mailmode, name,
  9245. X                is_subscribers) && !strcmp (mailmode, DIGEST))
  9246. X      append_to_digest = TRUE;
  9247. X    --offset;
  9248. X      }
  9249. X  }
  9250. X  else {
  9251. X    if (!send_to_subscribers) {  /* -r: Check if restricted mail has arrived */
  9252. X      rewind (restricted);
  9253. X      while (!feof (restricted)) {
  9254. X        alternate_file = TRUE;
  9255. X        restricted_subscriber[0] = RESET (recipient_file);
  9256. X        fscanf (restricted, "%s %s", restricted_subscriber, recipient_file);
  9257. X        upcase (restricted_subscriber);
  9258. X        if (!strcmp (restricted_subscriber, sender)) {
  9259. X        if (!strcmp (recipient_file, NO_RECIPIENT_FILE)) {
  9260. X        /* Do not forward to anyone */
  9261. X        report_progress (report, "No alternate recipient file specified. \
  9262. XMessage ignored.\n", FALSE);
  9263. X        return FALSE;
  9264. X      }
  9265. X      /* Restricted mail; forward message only to the people listed
  9266. X         in recipient_file */
  9267. X      OPEN_FILE (recipient_list, recipient_file, "r", "do_distribute");
  9268. X      report_progress (report, tsprintf ("Restricted mail. Distributing \
  9269. Xonly to individuals listed in %s", recipient_file), TRUE);
  9270. X      break;
  9271. X        }
  9272. X      }
  9273. X    }
  9274. X  }
  9275. X  if (!mail_remnants)
  9276. X    rewind (recipient_list);
  9277. X  while (!feof (recipient_list)) { /* Send to all of them */
  9278. X
  9279. X    if (!read_recipient (recipient_list, subscriber, mailmode, name,
  9280. X             is_subscribers))
  9281. X      continue;
  9282. X
  9283. X    if (is_digest) {
  9284. X      if (strcmp (mailmode, DIGEST))
  9285. X    continue;
  9286. X    }
  9287. X    else if (!strcmp (mailmode, DIGEST)) {
  9288. X      append_to_digest = TRUE;
  9289. X      continue;
  9290. X    }
  9291. X    else if (!strcmp (mailmode, NOACK)) {
  9292. X      upcase (subscriber);
  9293. X      if (!strcmp (subscriber, sender) || !strcmp (subscriber, originator))
  9294. X    continue;
  9295. X    }
  9296. X    else if (!strcmp (mailmode, POSTPONE))  /* No email to this subscriber */
  9297. X      continue;
  9298. X    else if (mailmode[0] != EOS && strcmp (mailmode, ACK)) {
  9299. X      syscom ("echo Unrecognized mail mode %s for recipient %s in %s | \
  9300. X%s %s %s",
  9301. X          mailmode, subscriber, file, UCB_MAIL, sys.manager,
  9302. X          sys.lists[listid].owner);
  9303. X      report_progress (report, tsprintf ("\ndo_distribute(): Unrecognized mail \
  9304. Xmode %s in %s", mailmode, file), TRUE);
  9305. X      continue;
  9306. X    }
  9307. X    RESET (senders_subject);
  9308. X    strcpy (senders_subject, subject_copy);
  9309. X    if (multi_recip) {
  9310. X      if ((multi_recipients[nrecipients] =
  9311. X       (char *) malloc ((strlen (subscriber) + 1) * sizeof (char)))
  9312. X      == NULL)
  9313. X        report_progress (report, "\ndo_distribute(): malloc() failed", TRUE),
  9314. X    gexit (11);
  9315. X      strcpy (multi_recipients[nrecipients++], locase (subscriber));
  9316. X    }
  9317. X    /* Prepare header */
  9318. X    if (posting) {
  9319. X      if (sys.options & POST_MAIL) /* Post to news group */
  9320. X    create_news_header (&forwardmail, mailforwardf, original_sender,
  9321. X                originator, name, senders_subject);
  9322. X      else if (sys.options & GATE_MAIL) /* Gate to news gateway */
  9323. X    create_gate_header (&forwardmail, mailforwardf, original_sender,
  9324. X                originator, subscriber, name, senders_subject),
  9325. X    posting = FALSE;
  9326. X      if (!copy_msg (forwardmail, message_file, posting, original_sender,
  9327. X             lines_to_skip, subscribed, check_size))
  9328. X    return FALSE;
  9329. X    }
  9330. X    else { /* Regular mail */
  9331. X      if (multi_recip) { /* Multi recipient header */
  9332. X    if (nrecipients == maxrecipients) {
  9333. X      create_multi_recipient_header (&forwardmail, mailforwardf,
  9334. X                     original_sender, originator,
  9335. X                     tsprintf ("Multiple recipients of \
  9336. Xlist <%s>", sys.lists[listid].address),
  9337. X                     senders_subject, nrecipients);
  9338. X      if (!copy_msg (forwardmail, message_file, posting, original_sender,
  9339. X             lines_to_skip, subscribed, check_size))
  9340. X        return FALSE;
  9341. X    }
  9342. X      }
  9343. X      else { /* Single recipient header */
  9344. X    create_header (&forwardmail, mailforwardf, original_sender, originator,
  9345. X               subscriber, senders_subject, FALSE, FALSE, FALSE);
  9346. X    if (!copy_msg (forwardmail, message_file, posting, original_sender,
  9347. X               lines_to_skip, subscribed, check_size))
  9348. X      return FALSE;
  9349. X      }
  9350. X    }
  9351. X    if (sendmail (subscriber, posting, multi_recip, nrecipients, maxrecipients,
  9352. X          mailforwardf))
  9353. X      update_unprocessed (unprocessed, posting, multi_recip, nrecipients);
  9354. X    if (nrecipients == maxrecipients)
  9355. X      nrecipients = 0;
  9356. X  }
  9357. X  if (alternate_file)  /* Close alternate recipient file */
  9358. X    fclose (recipient_list);
  9359. X
  9360. X  if (multi_recip && (nrecipients != 0)) { /* Left overs */
  9361. X    create_multi_recipient_header (&forwardmail, mailforwardf,
  9362. X                   original_sender, originator,
  9363. X                   tsprintf ("Multiple recipients of list <%s>",
  9364. X                         sys.lists[listid].address),
  9365. X                   senders_subject, nrecipients);
  9366. X    if (copy_msg (forwardmail, message_file, posting, original_sender,
  9367. X          lines_to_skip, subscribed, check_size))
  9368. X      sendmail (subscriber, posting, multi_recip, nrecipients, nrecipients, 
  9369. X            mailforwardf),
  9370. X      update_unprocessed (unprocessed, posting, multi_recip, nrecipients);
  9371. X    else
  9372. X      return FALSE;
  9373. X  }
  9374. X  return TRUE;
  9375. X}
  9376. X
  9377. X/*
  9378. X  Increment count of number of recipients that have received the current
  9379. X  message.
  9380. X*/
  9381. X
  9382. Xvoid update_unprocessed (char *unprocessed, BOOLEAN posting,
  9383. X             BOOLEAN multi_recip, int nrecipients)
  9384. X{
  9385. X  int nproc = 1, offset;
  9386. X  FILE *f;
  9387. X  struct stat stat_buf;
  9388. X
  9389. X  if (stat (unprocessed, &stat_buf) || stat_buf.st_size <= 0)
  9390. X    return;
  9391. X  if (multi_recip && !posting)
  9392. X    nproc = nrecipients;
  9393. X  OPEN_FILE (f, unprocessed, "r", "update_unprocessed");
  9394. X  fscanf (f, "%d", &offset);
  9395. X  fclose (f);
  9396. X  OPEN_FILE (f, unprocessed, "w", "update_unprocessed");
  9397. X  fprintf (f, "%d\n", offset + nproc);
  9398. X  fclose (f);
  9399. X}
  9400. X
  9401. X/*
  9402. X  Remove the message that was just delivered to everybody from the
  9403. X  unprocessed file.
  9404. X*/
  9405. X
  9406. Xvoid update_unprocessed_messages (char *unprocessed)
  9407. X{
  9408. X  FILE *in, *out;
  9409. X  char line [MAX_LINE];
  9410. X
  9411. X  OPEN_FILE (in, unprocessed, "r", "update_unprocessed_messages");
  9412. X  OPEN_FILE (out, unprocessed_tmp, "w", "update_unprocessed_messages");
  9413. X  if (!feof (in))
  9414. X    fgets (line, MAX_LINE - 2, in); /* Skip first "From " */
  9415. X  RESET (line);
  9416. X  while (!feof (in) &&
  9417. X         (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE))))
  9418. X    fgets (line, MAX_LINE - 2, in);
  9419. X  while (!feof (in)) /* Copy rest of messages */
  9420. X    fputs (line, out),
  9421. X    RESET (line),
  9422. X    fgets (line, MAX_LINE - 2, in);
  9423. X  fclose (in);
  9424. X  fclose (out);
  9425. X  mv (unprocessed_tmp, unprocessed);
  9426. X}
  9427. X
  9428. X/*
  9429. X  Copy the original message from message_file to the outgoing message.
  9430. X  Skip first "skip" lines. Reject it if it messages have a certain
  9431. X  limit, and that limit is exceeded (only when not distributing a digest).
  9432. X*/
  9433. X
  9434. XBOOLEAN copy_msg (FILE *forwardmail, char *message_file, BOOLEAN posting,
  9435. X          char *sender, long int lines_to_skip, BOOLEAN subscribed,
  9436. X          BOOLEAN check_size)
  9437. X{
  9438. X  FILE *msg;
  9439. X  char line [MAX_LINE];
  9440. X  char original_sender [MAX_LINE];
  9441. X  long int count = 0, line_no = 0;
  9442. X
  9443. X  OPEN_FILE (msg, message_file, "r", "copy_msg");
  9444. X  while (!feof (msg)) { /* Copy actual message */
  9445. X    RESET (line);
  9446. X    fgets (line, MAX_LINE - 2, msg);
  9447. X    line_no++;
  9448. X
  9449. X    if (line_no > lines_to_skip)
  9450. X      fprintf (forwardmail, "%s", line);
  9451. X
  9452. X    count += strlen (line);
  9453. X    message_rejected = FALSE;
  9454. X    if (check_size &&
  9455. X    (sys.options & LIMIT_MSG) && (count > sys.limits.msg) &&
  9456. X    subscribed != FALSE && subscribed != PEER && subscribed != NEWS) {
  9457. X      fclose (forwardmail);
  9458. X      rewind (msg);
  9459. X      strcpy (original_sender, sender);
  9460. X      extract_address (original_sender);
  9461. X      create_header (&forwardmail, mailforwardf, sys.lists[listid].address, 
  9462. X             sys.lists[listid].address, original_sender,
  9463. X             "Posting rejected", COPY_OWNER (ccerrors), FALSE, TRUE);
  9464. X      fprintf (forwardmail, "Your posting to list %s was rejected.\n\
  9465. XReason: message size limit exceeded (maximum allowed: %ld bytes)\n\
  9466. XThe first few lines of your message are included herein for reference:\n\n",
  9467. X           sys.lists[listid].alias, sys.limits.msg);
  9468. X      report_progress (report, "Message rejected: maximum size exceeded",
  9469. X               TRUE);
  9470. X      message_rejected = TRUE;
  9471. X      count = 0;
  9472. X      while (!feof (msg) && count < 10)
  9473. X    RESET (line),
  9474. X    fgets (line, MAX_LINE - 2, msg),
  9475. X    fprintf (forwardmail, "%s", line),
  9476. X    ++count;
  9477. X      COMPLETE_TELNET (forwardmail);
  9478. X      fclose (forwardmail);
  9479. X      fclose (msg);
  9480. X      sendmail (sender, FALSE, FALSE, 0, 0, mailforwardf);
  9481. X      return FALSE;
  9482. X    }
  9483. X  }
  9484. X  if (!posting && (sys.options & USE_TELNET))
  9485. X    COMPLETE_FILE (forwardmail);
  9486. X  fclose (forwardmail);
  9487. X  fclose (msg);
  9488. X  return TRUE;
  9489. X}
  9490. X
  9491. X/*
  9492. X  Send email (to subscribers/news/gateways/peers). It may send one single
  9493. X  copy to one recipient, or one copy to multiple recipients.
  9494. X*/
  9495. X
  9496. XBOOLEAN sendmail (char *subscriber, BOOLEAN posting, BOOLEAN multi_recip,
  9497. X          int nrecipients, int maxrecipients, char *mailforwardf)
  9498. X{
  9499. X  char *buf;
  9500. X  int size, i;
  9501. X
  9502. X  /* Form  sendmail command */
  9503. X  if (posting && (sys.options & POST_MAIL)) { /* Post to news */
  9504. X    if (syscom ("%s -h < %s > %s 2> %s", INEWS, mailforwardf, INEWS_REPLY,
  9505. X        INEWS_REPLY)) {
  9506. X      FILE *f = fopen (mailforwardf, "r");
  9507. X      char line [MAX_LINE], match [MAX_LINE];
  9508. X      while (f && !feof (f)) {
  9509. X    RESET (line);
  9510. X    fgets (line, MAX_LINE - 2, f);
  9511. X    strcpy (match, "\\1");
  9512. X    if (re_strcmp (FROM, line, match) > 0) {
  9513. X      sprintf (line, "%s", line + strlen (match)); /* Save From: */
  9514. X      line [strlen (line) - 1] = EOS; /* \n -> \0 */
  9515. X      extract_address (line);
  9516. X      break;
  9517. X    }
  9518. X      }
  9519. X      if (f)
  9520. X    fclose (f);
  9521. X      syscom ("%s -s \"Posting to `grep '^Newsgroups:' %s | \
  9522. Xawk '{ print $2 }'` failed: \" %s %s < %s",
  9523. X          UCB_MAIL, mailforwardf, line, sys.lists[listid].owner,
  9524. X          INEWS_REPLY);
  9525. X      unlink (INEWS_REPLY);
  9526. X    }
  9527. X  }
  9528. X  else { /* Send email */
  9529. X    if (multi_recip) { 
  9530. X      if (nrecipients == maxrecipients) {
  9531. X    if ((sys.options & USE_TELNET) == 0) { /* Line up recipients */
  9532. X      size = strlen (sys.mail.method) + strlen (multi_recipients[0]) +
  9533. X        strlen (mailforwardf) + 1 + 1;
  9534. X      if ((buf = (char *) malloc (size * sizeof (char))) == NULL)
  9535. X        report_progress (report, "\nsendmail(): malloc() failed", TRUE),
  9536. X        gexit (11);
  9537. X      sprintf (buf, "%s %s", sys.mail.method, multi_recipients[0]);
  9538. X      for (i = 1; i < nrecipients; i++)
  9539. X        size += strlen (multi_recipients[i]) + 2,
  9540. X        buf = (char *) realloc (buf, size * sizeof (char)),
  9541. X        sprintf (buf + strlen (buf), " %s", multi_recipients[i]);
  9542. X      if ((int) strlen (buf) > SHELL_CHAR_LIMIT)
  9543. X        report_progress (report,
  9544. X                 tsprintf ("Too many multiple \
  9545. Xrecipients: buffer limit (%d) exceeded by %d characters:\n%s", 
  9546. X                       SHELL_CHAR_LIMIT, strlen (buf) -
  9547. X                       SHELL_CHAR_LIMIT, buf), TRUE),
  9548. X        gexit (9);
  9549. X      syscom ("%s < %s", buf, mailforwardf);
  9550. X      free ((char *) buf);
  9551. X    }
  9552. X    else if (sys.options & USE_SYSMAIL)
  9553. X      sysmail (mailforwardf);
  9554. X    else /* telnet */
  9555. X      syscom ("%s < %s", sys.mail.method, mailforwardf);
  9556. X    return TRUE;
  9557. X      }
  9558. X    }
  9559. X    else  /* Single recipient */
  9560. X      if (sys.options & USE_SYSMAIL)
  9561. X    sysmail (mailforwardf);
  9562. X      else
  9563. X    extract_address (locase (subscriber)),
  9564. X        syscom ("%s '%s' < %s", sys.mail.method,
  9565. X                (((sys.options & USE_TELNET) == 0) ? subscriber : ""),
  9566. X                mailforwardf);
  9567. X    return TRUE;
  9568. X  }
  9569. X  return FALSE;
  9570. X}
  9571. X
  9572. Xvoid usage ()
  9573. X{
  9574. X  fprintf (stderr, "Usage: list <-L LIST_ALIAS> [-r] [-m #] [-1] [-f] [-e] \
  9575. X[-s] [-p] [-P] [-v] [-M] [-d] [-i address] [-Z] [-D]\n\
  9576. X-L: Process LIST_ALIAS (LIST_ALIAS has to be all in capital letters).\n\
  9577. X-r: Restricted mail.\n\
  9578. X-m: Specify number of multiple recipients in one outgoing message.\n\
  9579. X-1: Execute only once.\n\
  9580. X-f: Forward rejected messages to the list's owner.\n\
  9581. X-e: Echo reports to the screen.\n\
  9582. X-s: Do not check for subscriptions.\n\
  9583. X-p: Replies to posted (to news) messages will go to the author.\n\
  9584. X-P: Replies to distributed messages will go to the author.\n\
  9585. X-v: Version number.\n\
  9586. X-M: Moderated list.\n\
  9587. X-d: Distribute digest.\n\
  9588. X-i: Send partial digest to 'address'.\n\
  9589. X-Z: Turn off automatic compression of archived messages.\n\
  9590. X-D: Turn debug on.\n");
  9591. X  exit (3);
  9592. X}
  9593. X
  9594. Xvoid list_config (char *alias)
  9595. X{
  9596. X  if (!alias)
  9597. X    return;
  9598. X  setup_string (subscribersf, alias, SUBSCRIBERS);
  9599. X  setup_string (headersf, alias, HEADERS);
  9600. X  setup_string (restrictedf, alias, RESTRICTED);
  9601. X  setup_string (newsf, alias, NEWSF);
  9602. X  setup_string (peersf, alias, PEERS);
  9603. X  setup_string (aliasesf, alias, ALIASES);
  9604. X  setup_string (ignoredf, alias, IGNORED);
  9605. X  setup_string (list_mail_f, alias, LIST_MAIL_FILE);
  9606. X  setup_string (list_moderated_f, alias, LIST_MODERATED_F);
  9607. X  setup_string (mboxf, alias, MBOX);
  9608. X  setup_string (msg_nof, alias, MSG_NO);
  9609. X  setup_string (mailforwardf, alias, MAILFORWARD);
  9610. X  setup_string (msgf, alias, MSG);
  9611. X  setup_string (archivef, alias, ARCHIVE);
  9612. X  setup_string (digest_nof, alias, DIGEST_NO);
  9613. X  setup_string (digest_tocf, alias, DIGEST_TOC);
  9614. X  setup_string (digest_msgf, alias, DIGEST_MSG);
  9615. X  setup_string (digest_timef, alias, DIGEST_TIME);
  9616. X  setup_string (headerf, alias, HEADER);
  9617. X  setup_string (mail_copyf, alias, MAIL_COPY);
  9618. X  setup_string (report_listf, alias, REPORT_LIST);
  9619. X  setup_string (message_idsf, alias, MESSAGE_IDS_F);
  9620. X  setup_string (unprocessed_digestf, alias, UNPROC_DIGEST);
  9621. X  setup_string (unprocessed_subscribersf, alias, UNPROC_SUBSCRIBERS);
  9622. X  setup_string (unprocessed_peersf, alias, UNPROC_PEERS);
  9623. X  setup_string (unprocessed_newsf, alias, UNPROC_NEWS);
  9624. X  setup_string (unprocessed_messages, alias, UNPROC_MESSAGES);
  9625. X  setup_string (unprocessed_tmp, alias, UNPROC_TMP);
  9626. X  setup_string (removed_usersf, alias, REMOVED_USERS);
  9627. X  setup_string (removed_aliasesf, alias, REMOVED_ALIASES);
  9628. X  setup_string (limitsf, alias, LIST_LIMITS);
  9629. X  setup_string (errorsf, alias, ERRORSF);
  9630. X  setup_string (errors2f, alias, ERRORS2F);
  9631. X  setup_string (checksumsf, alias, CHECKSUMS);
  9632. X}
  9633. X
  9634. Xvoid version ()
  9635. X{
  9636. X  fprintf (stderr, "%s\n", VERSION);
  9637. X  exit (0);
  9638. X}
  9639. X
  9640. X/*
  9641. X  Graceful exit. Remove pid file.
  9642. X*/
  9643. X
  9644. Xint gexit (int exitcode)
  9645. X{
  9646. X  unlink (PID_LIST);
  9647. X#ifdef GO_INTERACTIVE
  9648. X  /* Reset flag so that serverd will not wait for ever. */
  9649. X  if (sid >= 0 && V (sid, SEM_DLVR_MAIL) < 0)
  9650. X    report_progress (report, tsprintf ("\ngexit(): Error V(); errno %d", 
  9651. X                       errno), TRUE);
  9652. X#endif
  9653. X  exit (exitcode);
  9654. X}
  9655. X
  9656. X/*
  9657. X  Write the text to fp, filling to 80 characters. Writing a null string
  9658. X  flushes the paragraph.
  9659. X
  9660. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  9661. X*/
  9662. X
  9663. X#define LEN 79            /* to avoid wrapping on some terminals */
  9664. X
  9665. Xvoid fill_text (FILE *fp, char *s)
  9666. X{
  9667. X  static char buf [LEN + 1];
  9668. X  static int pos = 0;
  9669. X  char word [LEN + 1], *p;
  9670. X
  9671. X  if (*s == EOS) { /* Flush buffer */
  9672. X    if (pos)
  9673. X      fprintf (fp, "%s\n", buf),
  9674. X      pos = 0;
  9675. X    fprintf (fp, "\n");
  9676. X  }
  9677. X  else
  9678. X    while (*s) { /* Get a word */
  9679. X      for (p = word; (*s != EOS) && !isspace (*s); s++, p++)
  9680. X    *p = *s;
  9681. X      *p = EOS;
  9682. X
  9683. X      /* Flush line if it won't fit */
  9684. X      if ((pos + strlen (word) + (pos != 0)) > LEN)
  9685. X    fprintf (fp, "%s\n", buf),
  9686. X    pos = 0;
  9687. X
  9688. X      /* Add word to line, precede with space if not first word */
  9689. X      if (pos)
  9690. X    buf[pos++] = ' ';
  9691. X      strcpy (&buf[pos], word);
  9692. X      pos += (int) strlen (word);
  9693. X      buf[pos] = EOS;
  9694. X
  9695. X      /* Skip trailing spaces */
  9696. X      while (isspace(*s))
  9697. X    s++;
  9698. X    }
  9699. X}
  9700. X
  9701. X/*
  9702. X  Read a line from the recipients file, fill subscriber, mailmode and name.
  9703. X  Return TRUE if it's OK, FALSE if no subscriber found.
  9704. X*/
  9705. X
  9706. XBOOLEAN read_recipient (FILE *fp, char *subscriber, char *mailmode, char *name,
  9707. X            BOOLEAN is_subscribers)
  9708. X{
  9709. X  char othermode [MAX_LINE];
  9710. X  int i;
  9711. X  FILE *f;
  9712. X
  9713. X  othermode[0] = mailmode[0] = name[0] = RESET (subscriber);
  9714. X  if (!extract_subscriber (fp, subscriber, FALSE)) {
  9715. X    fgets (othermode, MAX_LINE - 2, fp); /* Skip to eoln */
  9716. X    NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS(subscriber, "read_recipient", FALSE);
  9717. X    return FALSE;
  9718. X  }
  9719. X  if (subscriber[0] == EOS)
  9720. X    return FALSE;
  9721. X  fscanf (fp, "%s ", mailmode);
  9722. X
  9723. X  if (is_subscribers)
  9724. X    for (i = 1; i < (MAX_SET_OPTIONS - 1); i++) /* Skip unused options */
  9725. X      fscanf (fp, "%s ", othermode);
  9726. X  fgets (name, MAX_LINE - 2, fp);
  9727. X  if (name [0] != EOS && name [strlen (name) - 1] == '\n')
  9728. X    name [strlen (name) - 1] = EOS;
  9729. X  upcase (mailmode);
  9730. X
  9731. X  return TRUE;
  9732. X}
  9733. X
  9734. X/*
  9735. X  Count the number of lines in a file.
  9736. X
  9737. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  9738. X*/
  9739. X
  9740. Xlong int count_lines_in_file (FILE *fp)
  9741. X{
  9742. X  long int lines = 0;
  9743. X  char line [MAX_LINE];
  9744. X
  9745. X  if (fp)
  9746. X    while (!feof (fp)) {
  9747. X      RESET (line);
  9748. X      fgets (line, MAX_LINE - 2, fp);
  9749. X      if (line[0] != EOS)
  9750. X    ++lines;
  9751. X    }
  9752. X
  9753. X  return lines;
  9754. X}
  9755. X
  9756. X/*
  9757. X  Put the digest_toc and digest_msg files together to make a digest
  9758. X  in unprocessed_digestf.
  9759. X
  9760. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  9761. X*/
  9762. X
  9763. Xvoid digest_make (BOOLEAN to_everyone)
  9764. X{
  9765. X  FILE *ofp, *ifp;
  9766. X  char line1 [MAX_LINE], line2 [MAX_LINE], end_of_digest [MAX_LINE];
  9767. X  int i, topics = 0, ntopics = 0;
  9768. X
  9769. X  OPEN_FILE (ofp, (to_everyone ? unprocessed_digestf : msgf), "w",
  9770. X         "digest_make");
  9771. X  fprintf (ofp, "\t\t\t    %s\n\nTopics covered in this issue include:\n\n",
  9772. X       tsprintf ("%s Digest %d", list_alias, ++digest_msg));
  9773. X
  9774. X  OPEN_FILE (ifp, digest_tocf, "r", "digest_make");
  9775. X  while (!feof (ifp)) {
  9776. X    line1[0] = RESET (line2);
  9777. X    fgets (line1, MAX_LINE - 2, ifp);
  9778. X    fgets (line2, MAX_LINE - 2, ifp);
  9779. X    if (line1[0] != EOS)
  9780. X      fprintf (ofp, "%3d) %s\tby %s", ++ntopics, line1, line2);
  9781. X  }
  9782. X  fclose (ifp);
  9783. X
  9784. X  fprintf (ofp, "\n------------------------------------------\
  9785. X----------------------------\n");
  9786. X
  9787. X  OPEN_FILE (ifp, digest_msgf, "r", "digest_make");
  9788. X  while (!feof (ifp)) {
  9789. X    RESET (line1);
  9790. X    fgets (line1, MAX_LINE - 2, ifp);
  9791. X    if (line1[0] != EOS)
  9792. X      fputs (line1, ofp);
  9793. X  }
  9794. X  fclose (ifp);
  9795. X
  9796. X  sprintf (end_of_digest, "\nEnd of %s Digest %d\n", list_alias, digest_msg);
  9797. X  fprintf (ofp, "%s", end_of_digest);
  9798. X  for (i = 0; i < strlen (end_of_digest) - 2; ++i)
  9799. X    fprintf (ofp, "*");
  9800. X  fprintf (ofp, "\n");
  9801. X  fclose (ofp);
  9802. X
  9803. X  if (to_everyone) {
  9804. X    unlink (digest_tocf);
  9805. X    unlink (digest_msgf);
  9806. X    OPEN_FILE (ofp, digest_timef, "w", "digest_make");
  9807. X    fprintf (ofp, "%ld\n", time (0));
  9808. X    fclose (ofp);
  9809. X  }
  9810. X
  9811. X  report_progress (report,
  9812. X           tsprintf ("%sDistributing %sdigest #%04d.", DIGEST_TIME_,
  9813. X                 (to_everyone ? "" : "partial "), digest_msg),
  9814. X           TRUE);
  9815. X
  9816. X  if (to_everyone) {
  9817. X    OPEN_FILE (digest_no, digest_nof, "w", "digest_make");
  9818. X    fprintf (digest_no, "%d\n", digest_msg);
  9819. X    fclose (digest_no);
  9820. X  }
  9821. X}
  9822. X
  9823. X/*
  9824. X  Distribute a digest.
  9825. X
  9826. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  9827. X*/
  9828. X
  9829. Xvoid digest_distribute (void)
  9830. X{
  9831. X  char subject1[MAX_LINE], subject2[MAX_LINE];
  9832. X  struct stat stat_buf;
  9833. X
  9834. X  sprintf (subject1, "%s digest %d", sys.lists[listid].alias, digest_msg);
  9835. X  strcpy (subject2, subject1);
  9836. X
  9837. X  if (!stat (unprocessed_digestf, &stat_buf) && stat_buf.st_size > 0)
  9838. X    distributions (SUBSCRIBED, NULL, unprocessed_digestf, ARCHIVE_DIGEST,
  9839. X           sys.lists[listid].address,
  9840. X           sys.lists[listid].address, subject1, subject2,
  9841. X           sys.lists[listid].address, 0, FALSE);
  9842. X  unlink (unprocessed_digestf);
  9843. X}
  9844. X
  9845. X/*
  9846. X  Copy message_file to a file in arch_dir, whose name is specified
  9847. X  by arch_spec.
  9848. X  arch_spec is interpreted like a printf format string.  The following
  9849. X  formats are recognized:
  9850. X  %m month        01 - 12
  9851. X  %d day of month    01 - 31
  9852. X  %y year               00 - 99
  9853. X  %j julian date    001 - 366
  9854. X  %h month name    Jan - Dec
  9855. X  %a contents of Archive-Name header line (cannot be used if arching digests)
  9856. X  %# digest number (only use this if archiving digests)
  9857. X  %1 first non-blank line of file
  9858. X  %v volume number (extracted from Volume # Number # line)
  9859. X  %n issue number (extracted from Volume # Number # line)
  9860. X  %% the character %
  9861. X  any other characters are entered into the name of the file
  9862. X  example: arch.%y%m%d
  9863. X  If there already is a file by that name, add additional characters
  9864. X  to make a unique file.
  9865. X
  9866. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  9867. X*/
  9868. X
  9869. Xvoid do_archive (char *header_file, char *message_file, char *subject,
  9870. X         BOOLEAN is_moderated)
  9871. X{
  9872. X  FILE *fp;
  9873. X  char fullpath [MAX_LINE], line [MAX_LINE], dirname [MAX_LINE],
  9874. X    report_msg [MAX_LINE], *src, *dst, *p, *filep;
  9875. X  int i, volume_num = -1, issue_num = -1;
  9876. X  BOOLEAN done_volume = FALSE;
  9877. X#ifdef ultrix
  9878. X  time_t time_is = 0;
  9879. X#else
  9880. X  long int time_is = 0;
  9881. X#endif
  9882. X  struct tm *t;
  9883. X  struct stat stat_buf;
  9884. X
  9885. X  time (&time_is);
  9886. X  t = localtime (&time_is);
  9887. X
  9888. X  strcpy (fullpath, sys.lists[listid].arch_dir);
  9889. X  dst = fullpath + strlen (fullpath);
  9890. X  *dst++ = '/';
  9891. X  filep = dst;        /* start of file name */
  9892. X
  9893. X  for (src = sys.lists[listid].arch_spec; *src != EOS; src++) {
  9894. X    if (*src == '%') {
  9895. X      /* found a %, if next char is a known format specifier, print the
  9896. X     appropriate value.  Otherwise just print the character, so %% prints
  9897. X     one %. */
  9898. X      switch (*++src) {
  9899. X      case 'm':        /* month number */
  9900. X    sprintf (dst, "%02d", t->tm_mon + 1);
  9901. X    dst += 2;
  9902. X    break;
  9903. X      case 'd':        /* day of month */
  9904. X    sprintf (dst, "%02d", t->tm_mday);
  9905. X    dst += 2;
  9906. X    break;
  9907. X      case 'y':        /* 2 digits of year */
  9908. X    sprintf (dst, "%02d", t->tm_year % 100);
  9909. X    dst += 2;
  9910. X    break;
  9911. X      case 'j':        /* julian date */
  9912. X    sprintf (dst, "%03d", t->tm_yday + 1);
  9913. X    dst += 3;
  9914. X    break;
  9915. X      case 'h':        /* short name of month */
  9916. X    strcpy (dst, mname[t->tm_mon]);
  9917. X    dst += 3;
  9918. X    break;
  9919. X      case 'a':        /* contents of Archive-Name: header line */
  9920. X    if (archive_name[0] == EOS)
  9921. X      if (!get_archive_name (message_file, archive_name)) {
  9922. X        reject_archive ("Archive-Name: name missing", subject);
  9923. X        return;
  9924. X      }
  9925. X    strcpy (dst, archive_name);
  9926. X    dst += strlen (archive_name);
  9927. X    break;
  9928. X      case '#':        /* digest number */
  9929. X    sprintf (dst, "%d", digest_msg);
  9930. X    dst += strlen (dst);
  9931. X    break;
  9932. X      case '1':        /* 1st word of 1st nonblank line of message */
  9933. X    OPEN_FILE (fp, message_file, "r", "do_archive");
  9934. X    while (!feof (fp)) {
  9935. X      RESET (line);
  9936. X      fgets (line, MAX_LINE - 2, fp);
  9937. X      if (line [0] != EOS && line [strlen (line) - 1] == '\n')
  9938. X        line [strlen (line) - 1] = EOS;
  9939. X      /* Skip leading blanks, truncate string at blank. */
  9940. X      for (p = line; *p && isspace (*p); p++);
  9941. X      if (*p) {
  9942. X        strcpy (archive_name, p);
  9943. X        for (p = archive_name; *p != EOS && !isspace (*p); p++);
  9944. X        *p = EOS;
  9945. X        break;
  9946. X      }
  9947. X      locase (archive_name);
  9948. X    }
  9949. X    fclose (fp);        
  9950. X    strcpy (dst, archive_name);
  9951. X    dst += strlen (archive_name);
  9952. X    break;
  9953. X      case 'v':
  9954. X    if (!done_volume) {
  9955. X      if (!get_volume (message_file, &volume_num, &issue_num)) {
  9956. X        reject_archive ("Volume number missing", subject);
  9957. X        return;
  9958. X      }
  9959. X      done_volume = TRUE;
  9960. X    }
  9961. X    sprintf (dst, "%d", volume_num);
  9962. X    dst += strlen (dst);
  9963. X    break;
  9964. X      case 'n':
  9965. X    if (!done_volume) {
  9966. X      if (!get_volume (message_file, &volume_num, &issue_num)) {
  9967. X        reject_archive ("Issue number missing", subject);
  9968. X        return;
  9969. X      }
  9970. X      done_volume = TRUE;
  9971. X    }
  9972. X
  9973. X    sprintf (dst, "%d", issue_num);
  9974. X    dst += strlen(dst);
  9975. X    break;
  9976. X      default:
  9977. X    *dst++ = *src;
  9978. X      }
  9979. X    }
  9980. X    else
  9981. X      *dst++ = *src;
  9982. X  }
  9983. X  *dst = EOS;
  9984. X
  9985. X  if (filep == dst) { /* No name to archive */
  9986. X    reject_archive ("Archive name is blank", subject);
  9987. X    return;
  9988. X  }
  9989. X
  9990. X  if (re_strcmp ("/*\\.\\./", fullpath, NULL) > 0) {
  9991. X    /* Someone is trying to write an archive into a parent dir. */
  9992. X    reject_archive (tsprintf ("Archive file %s contains ..", fullpath),
  9993. X            subject);
  9994. X    return;
  9995. X  }
  9996. X  if (re_strcmp ("/", archive_name, NULL)) {
  9997. X    reject_archive (tsprintf ("Archive file %s contains directory", archive_name),
  9998. X            subject);
  9999. X    return;
  10000. X  }
  10001. X  for (i = 0; i < strlen (fullpath); i++)
  10002. X    if (!isalnum (fullpath[i]) && fullpath[i] != '.' && fullpath[i] != '/' &&
  10003. X    fullpath[i] != '@' && fullpath[i] != '#' && fullpath[i] != '%' &&
  10004. X    fullpath[i] != '-' && fullpath[i] != '_') {
  10005. X      reject_archive (tsprintf ("Archive file %s contains invalid character '%c'",
  10006. X           fullpath, fullpath[i]), subject);
  10007. X      return;
  10008. X    }
  10009. X
  10010. X  /* Create archive dir if needed.  Can't use arch_dir, there might be
  10011. X     /'s in %1 or %a or arch_spec. */
  10012. X  strcpy (dirname, fullpath);
  10013. X  if (p = strrchr (dirname, '/'))
  10014. X    *p = EOS;
  10015. X  if (!mkdir1 (dirname, report_msg, mask)) {
  10016. X    reject_archive (report_msg, subject);
  10017. X    return;
  10018. X  }
  10019. X
  10020. X/*
  10021. X  If the file already exists, append .1, .2 and so on.
  10022. X  for (i = 1; access (fullpath, 0) == 0; i++)
  10023. X    sprintf (dst, ".%d", i);
  10024. X*/
  10025. X
  10026. X  report_progress (report, tsprintf ("Archiving in %s", fullpath), TRUE);
  10027. X
  10028. X  if (!no_compression &&
  10029. X      stat (fullpath, &stat_buf))    /* Compress previous archive files */
  10030. X    syscom ("compress %s/* > /dev/null 2>&1 < /dev/null", dirname),
  10031. X    syscom ("uncompress %s/%s.Z %s/%s.Z > /dev/null 2>&1 < /dev/null", dirname,
  10032. X        DIRF, dirname, INDEX);
  10033. X  if (is_moderated) { /* Skip message lines before appending */
  10034. X    char line [MAX_LINE];
  10035. X    FILE *in, *out;
  10036. X    if (header_file)
  10037. X      cat_append (header_file, fullpath);
  10038. X    OPEN_FILE (in, message_file, "r", "do_archive");
  10039. X    OPEN_FILE (out, fullpath, "a", "do_archive");
  10040. X    while (!feof (in)) {
  10041. X      RESET (line);
  10042. X      fgets (line, MAX_LINE - 2, in);
  10043. X      if (line [0] != EOS && line [strlen (line) - 1] == '\n')
  10044. X    line [strlen (line) - 1] = EOS;
  10045. X      if (!strcmp (line, MESSAGE_SEPARATOR))
  10046. X    break;
  10047. X    }
  10048. X    if (feof (in))    /* No message separator, so archive the whole msg */
  10049. X      rewind (in);
  10050. X    while (!feof (in))
  10051. X      RESET (line),
  10052. X      fgets (line, MAX_LINE - 2, in),
  10053. X      fputs (line, out);
  10054. X    fclose (in);
  10055. X    fclose (out);
  10056. X  }
  10057. X  else {
  10058. X    if (header_file)
  10059. X      cat_append (header_file, fullpath);
  10060. X    cat_append (message_file, fullpath);
  10061. X  }
  10062. X  chmod (fullpath, 0644 & (0644 ^ otoi (archives_mask)));
  10063. X
  10064. X  if (*sys.lists[listid].farch_dir != EOS)
  10065. X    farch (sys.lists[listid].arch_dir, sys.lists[listid].farch_dir,
  10066. X       sys.lists[listid].arch_pass, fullpath, filep, subject);
  10067. X}
  10068. X
  10069. X/*
  10070. X  Add the archive file to the DIR in farch_dir.
  10071. X
  10072. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  10073. X*/
  10074. X
  10075. Xvoid farch (char *arch_dir, char *farch_dir, char *password, char *fullpath,
  10076. X        char *file_part, char *subject)
  10077. X{
  10078. X  FILE *fin, *fout;
  10079. X  long int dummy;
  10080. X  char dir [MAX_LINE], file [MAX_LINE], dirf [MAX_LINE],
  10081. X  full_arch_dir [MAX_LINE], full_farch_dir [MAX_LINE], error [MAX_LINE],
  10082. X  desc [MAX_LINE], _file [MAX_LINE];
  10083. X  char *p;
  10084. X  struct stat stat_buf;
  10085. X  BOOLEAN continued = FALSE, found;
  10086. X
  10087. X  /* If file_part contains a directory, extract that into dir to append
  10088. X     to farch_dir and to arch_dir. */
  10089. X  strcpy (dir, file_part);
  10090. X  if (p = strrchr(dir, '/'))
  10091. X    strcpy (file, p + 1),
  10092. X    *p = EOS,
  10093. X    sprintf (full_arch_dir, "%s/%s", arch_dir, dir),
  10094. X    sprintf (full_farch_dir, "%s/%s", farch_dir, dir);
  10095. X  else
  10096. X    RESET (dir),
  10097. X    strcpy(file, file_part),
  10098. X    strcpy (full_arch_dir, arch_dir),
  10099. X    strcpy (full_farch_dir, farch_dir);
  10100. X  sprintf (dirf, "%s/%s/%s", ARCHIVE_DIR, full_farch_dir, DIRF);
  10101. X  if (!make_indexes (dirf, full_farch_dir, password, error, mask)) {
  10102. X    reject_archive (error, subject);
  10103. X    return;
  10104. X  }
  10105. X
  10106. X  sprintf (error, "%s.old", dirf);
  10107. X  mv (dirf, error);
  10108. X  OPEN_FILE (fin, error, "r", "farch");
  10109. X  OPEN_FILE (fout, dirf, "w", "farch");
  10110. X  stat (fullpath, &stat_buf);
  10111. X  found = FALSE;
  10112. X  while (!feof (fin)) { /* Get location and file-count of file */
  10113. X    RESET (_file);
  10114. X    fscanf (fin, "%s", _file);
  10115. X    if (_file[0] != EOS) {
  10116. X      locase (_file);
  10117. X      if (!strcmp (_file, file)) {
  10118. X    fprintf (fout, "%s 1 %ld", file, stat_buf.st_size);
  10119. X    fscanf (fin, "%d %d", &dummy, &dummy);
  10120. X    found = TRUE;
  10121. X    do { /* Get file description */
  10122. X      RESET (desc);
  10123. X      fgets (desc, MAX_LINE - 2, fin);
  10124. X      fputs (desc, fout);
  10125. X      if (desc[0] != EOS && desc[strlen (desc) - 1] == '\n')
  10126. X        desc[strlen (desc) - 1] = EOS;
  10127. X      continued = FALSE;
  10128. X      if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
  10129. X        continued = TRUE;
  10130. X    } while (continued);
  10131. X      }
  10132. X      else {
  10133. X    fprintf (fout, "%s", _file);
  10134. X    do { /* Get file description */
  10135. X      RESET (desc);
  10136. X      fgets (desc, MAX_LINE - 2, fin);
  10137. X      fputs (desc, fout);
  10138. X      if (desc[0] != EOS && desc[strlen (desc) - 1] == '\n')
  10139. X        desc[strlen (desc) - 1] = EOS;
  10140. X      continued = FALSE;
  10141. X      if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
  10142. X        continued = TRUE;
  10143. X    } while (continued);
  10144. X      }
  10145. X    }
  10146. X  }
  10147. X  if (!found)
  10148. X    fprintf (fout, "%s 1 %ld %s %s\n", file, stat_buf.st_size, full_arch_dir,
  10149. X         subject);
  10150. X  fclose (fin);
  10151. X  fclose (fout);
  10152. X  unlink (error);
  10153. X  chmod (dirf, 0644 & (0644 ^ otoi (archives_mask)));
  10154. X}
  10155. X
  10156. X/*
  10157. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  10158. X*/
  10159. X
  10160. Xvoid reject_archive (char *msg, char *subject)
  10161. X{
  10162. X  FILE *forwardmail = NULL;
  10163. X  char report_msg [MAX_LINE];
  10164. X
  10165. X  sprintf (report_msg, "Cannot archive: %s", msg);
  10166. X  report_progress (report, report_msg, TRUE);
  10167. X
  10168. X  create_header (&forwardmail, mailforwardf, sys.lists[listid].address,
  10169. X         sys.lists[listid].address, sys.lists[listid].owner,
  10170. X         subject, FALSE, TRUE, TRUE);
  10171. X  fprintf (forwardmail, "Cannot archive: %s\n", msg);
  10172. X  fprintf (forwardmail, "arch_dir: %s\n", sys.lists[listid].arch_dir);
  10173. X  fprintf (forwardmail, "arch_spec: %s\n", sys.lists[listid].arch_spec);
  10174. X  fprintf (forwardmail, "Here is the message that was not archived:\n\
  10175. X------------------------------------------------------------------------------\
  10176. X\n\n");
  10177. X
  10178. X  if (copy_msg (forwardmail, msgf, FALSE, sys.lists[listid].address, 0, FALSE,
  10179. X        FALSE))
  10180. X    sendmail (sys.lists[listid].owner, FALSE, FALSE, 0, 0,
  10181. X          mailforwardf);
  10182. X}
  10183. X
  10184. X/*
  10185. X  Look for a line like "volume <number> number <number>" and store
  10186. X  numbers in volume_num and issue_num.
  10187. X
  10188. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  10189. X*/
  10190. X
  10191. XBOOLEAN get_volume (char *message_file, int *volume_num, int *issue_num)
  10192. X{
  10193. X  FILE *fp;
  10194. X  char line [MAX_LINE], *p;
  10195. X  BOOLEAN found = FALSE;
  10196. X
  10197. X  OPEN_FILE (fp, message_file, "r", "get_volume");
  10198. X  while (!feof (fp) && !found) {
  10199. X    RESET (line);
  10200. X    fgets (line, MAX_LINE - 2, fp);
  10201. X    if (line [0] != EOS && line [strlen (line) - 1] == '\n')
  10202. X      line [strlen (line) - 1] = EOS;
  10203. X
  10204. X    locase (line);
  10205. X
  10206. X    for (p = line; *p != EOS && isspace (*p); p++);
  10207. X    if (strncmp (p, "volume", strlen ("volume")))
  10208. X      continue;
  10209. X
  10210. X    for (p += strlen ("volume"); *p != EOS && isspace (*p); p++);
  10211. X    if (!isdigit (*p))
  10212. X      continue;
  10213. X
  10214. X    *volume_num = atoi (p);
  10215. X    for (; *p != EOS && isdigit (*p); p++);
  10216. X
  10217. X    for (; *p != EOS && isspace (*p); p++);
  10218. X    if (strncmp (p, "number", strlen ("number")))
  10219. X      continue;
  10220. X
  10221. X    for (p += strlen ("number"); *p != EOS && isspace (*p); p++);
  10222. X    if (!isdigit (*p))
  10223. X      continue;
  10224. X
  10225. X    *issue_num = atoi (p);
  10226. X    found = TRUE;
  10227. X  }
  10228. X
  10229. X  fclose (fp);
  10230. X  return found;
  10231. X}
  10232. X
  10233. X/*
  10234. X  Get the Archive-Name: if any.
  10235. X*/
  10236. X
  10237. XBOOLEAN get_archive_name (char *message_file, char *archive_name)
  10238. X{
  10239. X  FILE *fp;
  10240. X  char error [MAX_LINE], line[MAX_LINE];
  10241. X
  10242. X  OPEN_FILE (fp, message_file, "r", "get_archive_name");
  10243. X  while (!feof (fp)) {
  10244. X    RESET (line);
  10245. X    fgets (line, MAX_LINE - 2, fp);
  10246. X    locase (line);
  10247. X    clean_request (line);
  10248. X    if (re_strcmp (ARCHIVE_NAME, line, NULL) > 0) {
  10249. X      sscanf (line, "%s %s", error, archive_name);
  10250. X      fclose (fp);
  10251. X      return TRUE;
  10252. X    }
  10253. X  }
  10254. X  fclose (fp);
  10255. X  return FALSE;
  10256. X}
  10257. X
  10258. X/*
  10259. X  Check if the daily limit of messages posted has been exceeded and return
  10260. X  immediately; otherwise, distribute no more than the limit minus messages
  10261. X  already posted and update the limits file.
  10262. X*/
  10263. X
  10264. XBOOLEAN limit_exceeded (char *limitsf, char *list_mail_f, char *mail_copyf)
  10265. X{
  10266. X  FILE *fin, *fout;
  10267. X  long int nmessages, mon, day, year;
  10268. X#ifdef ultrix
  10269. X  time_t time_is;
  10270. X#else
  10271. X  long int time_is;
  10272. X#endif
  10273. X  struct tm *t;
  10274. X  char line [MAX_LINE];
  10275. X  char *tmprest;
  10276. X
  10277. X  nmessages = mon = day = year = 0;
  10278. X  if ((fin = fopen (limitsf, "r")))
  10279. X    fscanf (fin, "%d %d %d %d", &nmessages, &mon, &day, &year),
  10280. X    fclose (fin);
  10281. X  if (nmessages > sys.lists[listid].max_messages)
  10282. X    return TRUE;
  10283. X  OPEN_FILE (fin, list_mail_f, "r", "limit_exceeded");
  10284. X  OPEN_FILE (fout, mail_copyf, "w", "limit_exceeded");
  10285. X  while (!feof (fin) && nmessages < sys.lists[listid].max_messages) {
  10286. X    ++nmessages;
  10287. X    RESET (line);
  10288. X    fgets (line, MAX_LINE - 2, fin);
  10289. X    do {
  10290. X      fputs (line, fout);
  10291. X      RESET (line);
  10292. X      fgets (line, MAX_LINE - 2, fin);
  10293. X    } while (!feof (fin) &&
  10294. X         (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE))));
  10295. X    if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))
  10296. X      fseek (fin, -strlen (line), SEEK_CUR); /* Move back to beginning */
  10297. X  }
  10298. X  fclose (fout);
  10299. X  OPEN_FILE (fout, (tmprest = mystrdup (tmpnam (NULL))), "w", "limit_exceeded");
  10300. X  RESET (line);
  10301. X  while (!feof (fin))
  10302. X    RESET (line),
  10303. X    fgets (line, MAX_LINE - 2, fin),
  10304. X    fputs (line, fout);
  10305. X  fclose (fin);
  10306. X  fclose (fout);
  10307. X  mv (tmprest, list_mail_f);
  10308. X  free ((char *) tmprest);
  10309. X  time (&time_is);
  10310. X  t = localtime (&time_is);
  10311. X  echo (tsprintf ("%d %d %d %d", nmessages, t->tm_mon + 1, t->tm_mday,
  10312. X          t->tm_year), limitsf);
  10313. X  return FALSE;
  10314. X}
  10315. *-*-END-of-src/list.c-*-*
  10316. echo x - src/listproc.c
  10317. sed 's/^X//' >src/listproc.c <<'*-*-END-of-src/listproc.c-*-*'
  10318. X/*
  10319. X  ----------------------------------------------------------------------------
  10320. X  |                        MAILING LIST PROCESSOR                            |
  10321. X  |                                         |
  10322. X  |                             Version 6.0                     |
  10323. X  |                                                                          |
  10324. X  |                (or, when Computer Science gets to you)                   |
  10325. X  |                                                                          |
  10326. X  |                    Written by Anastasios Kotsikonas                      |
  10327. X  |                           (tasos@cs.bu.edu)                              |
  10328. X  |                                                                          |
  10329. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  10330. X  | whole and not in parts, as long as you do not remove or alter the author |
  10331. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  10332. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  10333. X  | provided for your personal use, you may not alter the functions         |
  10334. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  10335. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  10336. X  | any changes you may have made. No part of the source code bearing a         |
  10337. X  | copyright notice can be included in commercial software systems without  |
  10338. X  | written permission by the author.                         |
  10339. X  | By using this software you are bound by this agreement.             |
  10340. X  | This software comes with no warranties and cannot be sold for profit.    |
  10341. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  10342. X  | files when distributing this software.                                   |
  10343. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  10344. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  10345. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  10346. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  10347. X  | (ii).                                                                    |
  10348. X  ----------------------------------------------------------------------------
  10349. X
  10350. X  This is the system's server. People send requests to ListProcessor for
  10351. X  subscription, removal of subscription, general information request, etc.
  10352. X  In addition, list owners issue administrative requests.
  10353. X
  10354. X  The recognized user-commands are as follows:
  10355. X    help [command]
  10356. X    set <list> [<option> <arg[s]>]    option: mail, password, address, conceal
  10357. X                    arg: ack, noack, postpone, digest
  10358. X                    args: current-password new-password
  10359. X                    args: current-password new-address
  10360. X                    arg: yes, no
  10361. X    subscribe <list> <name>
  10362. X    unsubscribe <list> (alias signoff)
  10363. X    recipients <list> (alias review)
  10364. X    information <list>
  10365. X    statistics <list> {[subscriber email address(es)] | [-all]}
  10366. X    lists
  10367. X    which
  10368. X    index [archive | path-to-archive] [/password] [-all]
  10369. X    get <archive | path-to-archive> <filename> [/password] [parts]
  10370. X    search <archive | path-to-archive> [/password] [-all] <pattern>
  10371. X    fax <fax-number> <archive | path-to-archive> <filename> [/password] [parts]
  10372. X    run <list> [<password> cmd [args]]
  10373. X    release
  10374. X
  10375. X  List administration commands:
  10376. X    system <list> <password> <user-address> #<user-request>
  10377. X    reports <list> <password>
  10378. X    edit <list> <password> <file>
  10379. X    put <list> <password> <keyword> [args]
  10380. X    approve <list> <password> <tag>
  10381. X    discard <list> <password> <tag>
  10382. X
  10383. X  Manager oriented commands:
  10384. X    shutdown <password>
  10385. X    restart <password>
  10386. X    execute <password> #<prog> [args]
  10387. X
  10388. X  Above, <user-request> is any of the recognized user requests.
  10389. X
  10390. X  Commands are sent to ListProcessor one on each line of the message. The user
  10391. X  is notified of the first invalid request; all subsequent commands
  10392. X  are ignored -- imagine someone sending an entire book!! For each 
  10393. X  successfully completed command, a confirmation is sent back to the sender.
  10394. X  Commands/requests may be abbreviated.
  10395. X
  10396. X  USER ORIENTED REQUESTS:
  10397. X  -----------------------
  10398. X
  10399. X  The user may request help in general, or on a specific command; he can
  10400. X  'set list mail ack' in which case his/her messages to the list will be
  10401. X  echoed back to him/her, and 'set list mail noack' (the opposite);
  10402. X  A 'set list mail postpone' request will not send any messages to the
  10403. X  subscriber until he resets it to one of the other options (used to suppress
  10404. X  sending email temporarily). 'set list mail digest' will only send messages
  10405. X  periodically as digests. 'set list' with no arguments returns the current
  10406. X  values for all options. The user may reset his/her password with the
  10407. X  'set list password current-password new-password' request, and use this
  10408. X  password to alter the address he/she is subscribed with: 'set list address
  10409. X  current-password new-address'; he may hide his identity by issuing a
  10410. X  'set list conceal yes' request.
  10411. X
  10412. X  To subscribe to the list, a user has to give his/her full name; 
  10413. X  he/she may leave the list by issuing an 'unsubscribe' request;
  10414. X  a list of the current subscribers is obtained through a 'recipients' request;
  10415. X  a copy of the sender's message is also sent to peer lists in this case.
  10416. X  Moreover, general information is available by means of an 'information'
  10417. X  request, and finally 'statistics' compiles a count of messages sent by
  10418. X  each subscriber (unless specific subscriber address are given) as well as
  10419. X  a total count of messages on file; again, a copy of the message will be
  10420. X  forwarded to all peer lists. Private lists do not allow non-members to
  10421. X  execute 'recipients' and 'statistics' requests.
  10422. X
  10423. X  A list of all mailing lists served by this server can be obtained by
  10424. X  a 'lists' request.
  10425. X
  10426. X  A listing of all lists a person is subscribed in is available via a
  10427. X  'which' request.
  10428. X
  10429. X  Information on the current release of this server can be obtained by
  10430. X  a 'release' request.
  10431. X
  10432. X  Subscribers of a list may also run a set of UNIX commands as defined by the
  10433. X  system's manager via the 'run' request. Each command may have a different
  10434. X  password and may take arguments. Users receive the output from stdout and/or
  10435. X  stderr.
  10436. X
  10437. X  The system includes a means for users to obtain files. The files
  10438. X  can be placed anywhere in the system and are archived under
  10439. X              HOMEDIR/archives/*
  10440. X  Each of these archives has an index of subarchives and a directory
  10441. X  of files that can be obtained from that archive; there is a master
  10442. X  archive in archives/listproc: the file INDEX contains names and full paths
  10443. X  to all of the archives (including listproc); the file DIR is a directory 
  10444. X  of files that are archived under listproc. A user
  10445. X  may obtain a list of all the archives and their files by sending an
  10446. X  'index' request. That request followed by a specific archive will
  10447. X  send a list of files for that archive and all of its subsrchives.
  10448. X  The format of the INDEX file is as follows: one line per archive
  10449. X  with the following:
  10450. X
  10451. X     archive-name full-path-to-its-directory [password]
  10452. X
  10453. X  When listing subarchives in INDEX the following rule has to be followed:
  10454. X  the first entry is the archive itself; all first level subarchives follow
  10455. X  (let's say A, B and C), then all second level subarchives (starting with
  10456. X  A's subarchives, then listing B's and last C's), then all third level
  10457. X  subarchives, etc. No sibling archives may have the same name.
  10458. X
  10459. X  An archive is made private by putting a password after its full
  10460. X  path specification. This password has to be present in all parent
  10461. X  archives and is required for obtaining an index of that archive,
  10462. X  as well as any files from that archive.
  10463. X
  10464. X  A file can be obtained via a 'get' request, specifying the archive and
  10465. X  the file to get. It is possible that a file has been split in various
  10466. X  parts, in which case multiple emails with the various subparts will
  10467. X  be sent to the user. Note that only the master index is used in this
  10468. X  case for locating the archive. Individual parts of the split file may
  10469. X  be obtained by specifying them as arguments.
  10470. X
  10471. X  An archive's files may be searched for a pattern via the 'search' request.
  10472. X  The pattern is an egrep(1)-style regular expression with the additional
  10473. X  `&` (AND) and '~' (OR) loginal operators.
  10474. X
  10475. X  A file may be archived with the farch utility, or manually by
  10476. X  editing the DIR file of the target archive. The format is as follows:
  10477. X  one line per file containing the following information:
  10478. X
  10479. X  filename number-of-subparts size-of-each-part dir-where-found [Comments]
  10480. X
  10481. X  The restriction is that the actual disk file should be all in lower case.
  10482. X  Private archives require a password for obtaining files.
  10483. X
  10484. X  A new archive may be created by creating a subdirectory under
  10485. X  HOMEDIR/archives (the new directory may not be all in lower-case letters),
  10486. X  updating the master INDEX (archives/listproc/INDEX) and all lower-level
  10487. X  indeces (if any), creating a new INDEX file in the new directory with one
  10488. X  entry (the new archive itself), and creating an empty DIR file in the
  10489. X  same new directory.
  10490. X
  10491. X  The hierarchical structure is only logical and directory hierarchy does
  10492. X  not matter. All archives though have to be placed under HOMEDIR/archives.
  10493. X
  10494. X  All commands may be abbreviated except 'shutdown' and 'restart'.
  10495. X
  10496. X  LIST OWNER ORIENTED REQUESTS:
  10497. X  -----------------------------
  10498. X
  10499. X  The system includes support for list owners. These are list administrators
  10500. X  with special privileges on the system. They may issue requests on users'
  10501. X  behalf overriding any restriction set on regular users (these include
  10502. X  disabled commands also). The following requests are available to
  10503. X  list owners:
  10504. X
  10505. X    system <list> <password> <user-address> #<user-request>
  10506. X
  10507. X  This request overrides all system restrictions and executes <user-request>
  10508. X  on behalf of <user-address>; the address has to appear as listsed in the
  10509. X  .subscribers file, where applicable. The most frequent use of the 'system'
  10510. X  request is to subscribe a user to a private list. ListProcessor will send
  10511. X  a message to the owner igiving him the exact address and request to
  10512. X  issue back. For example:
  10513. X
  10514. X    system herc herc1 user1@foo.com #subscribe herc Foo Bar
  10515. X
  10516. X  As another example, to remove a user from a list, the owner issues:
  10517. X
  10518. X    system herc herc1 user1@foo.com #unsubscribe herc
  10519. X
  10520. X  Keep in mind that if the owner makes a syntax error in <user-request>,
  10521. X  <user-address> will be notified as if they issued the incorrect
  10522. X  request.
  10523. X
  10524. X  A list owner may obtain all reports pertinent to the list he is maintaining
  10525. X  by issuing the following request:
  10526. X
  10527. X    reports <list> <password>
  10528. X
  10529. X  This will send two mail messages: one with the current report and one with
  10530. X  the previously archived ones.
  10531. X
  10532. X  An owner may also obtain other files pertinent to his list via the
  10533. X  following request:
  10534. X
  10535. X    edit <list> <password> <file>
  10536. X
  10537. X  This will send a message containing the specified file.
  10538. X
  10539. X  A list owner may also add aliases to the .aliases file, add users to the
  10540. X  .ignored file, change the welcoming message in .welcome, change
  10541. X  the informative message in .info, change the .subscribers/.peers/.news etc
  10542. X  by way of the 'put' request:
  10543. X
  10544. X    put <list> <password> <keyword> [args]
  10545. X
  10546. X  The keyword defines the action to be taken; valid keywords are: alias,
  10547. X  ignore, welcome, info. To add an alias, the following request may be
  10548. X  issued:
  10549. X
  10550. X    put <list> <password> alias <new-alias> <address-as-subscribed>
  10551. X
  10552. X  Refer to the man pages for explanation on aliases. To add to the .ignored
  10553. X  file:
  10554. X
  10555. X    put <list> <password> ignore <address-as-subscribed-or-aliased>
  10556. X
  10557. X  To create new .welcome/.info/.aliases/.ignored/.subscribers/.news/.peers
  10558. X  files the following requests may be issued:
  10559. X
  10560. X    put <list> <password> welcome
  10561. X    put <list> <password> info
  10562. X    put <list> <password> aliases
  10563. X    put <list> <password> ignored
  10564. X    put <list> <password> subscribers
  10565. X    put <list> <password> news
  10566. X    put <list> <password> peers
  10567. X
  10568. X  After the request, all text that follows is assumed to be the message
  10569. X  to be copied until the end of this message. Thus no more requests can
  10570. X  be made in the same mail message (they are treated as regular text).
  10571. X
  10572. X  As a final note, list owners are authenticated by checking their
  10573. X  addresses in HOMEDIR/owners (a file containing all owners' addresses),
  10574. X  and verifying their passwords. There is no provision for adding restricted
  10575. X  users, adding new peers and connecting with news groups. These cases
  10576. X  have to be handled by the system's manager.
  10577. X
  10578. X  A list owner may also approve messages for posting to his moderated
  10579. X  list via an 'approve' request. ListProcessor forwards every new message
  10580. X  to the owner providing him with the message's tag number. The
  10581. X  owner then replies with:
  10582. X
  10583. X    approve <list> <password> <tag>
  10584. X
  10585. X  ListProcessor then finds the message with the provided tag and prepares
  10586. X  it for posting. To discard a message, the owner sends the following
  10587. X  request:
  10588. X
  10589. X    discard <list> <password> <tag>
  10590. X
  10591. X  MANAGER ORIENTED REQUESTS:
  10592. X  --------------------------
  10593. X
  10594. X  The entire system may be remotely shut down by way of a 'shutdown' request;
  10595. X  this request must be followed by a password that must match the one defined
  10596. X  in config. Note that this may result in requests being queued with the
  10597. X  'shutdown' one not being serviced; note thought that a copy of the original
  10598. X  requests can be found in MAIL_COPY as defined in listproc.h.
  10599. X  Likewise, the system may be remotely restarted by issuing a 'restart'
  10600. X  request with the proper password. Note that a 'restart' request has no
  10601. X  effect after a 'shutdown' (because the server is not running), and that
  10602. X  any requests queued with the 'restart' will be serviced (the system will
  10603. X  not restart until all requests are serviced).
  10604. X
  10605. X  ListProcessor lets the manager execute a command remotely via the 'execute'
  10606. X  request, and sends him the output from stdout and stderr in two separate
  10607. X  messages.
  10608. X
  10609. X  COMMAND LINE OPTIONS:
  10610. X    -1: Same as for the list program.
  10611. X    -r: This option may be repeated an infinite number of times and is
  10612. X        always followed by a valid ListProcessor command (as outlined above).
  10613. X        This forces a restriction to be placed on the specified command;
  10614. X        whenever a user makes such a request, the request will be rejected
  10615. X        if the number of users currently on the system is greater than
  10616. X        the threshold specified in listproc.h. This option was added due
  10617. X        to the fact that the 'statistics' request may take up a lot of
  10618. X        resources to complete.
  10619. X    -e: Echo reports to the screen.
  10620. X    -n: Do not notify peer servers.
  10621. X    -d: Disable a ListProcessor command. This makes totally unknown to the server.
  10622. X        However, help is still available for the particular request.
  10623. X    -a: Usually, subscriptions are automatic. This option turns automatic
  10624. X    subscription off for the specified list. Such requests will be
  10625. X    forwarded to manager for approval.
  10626. X    -b: The command that follows will be executed in batch mode.
  10627. X    -B: Process the batch queue.
  10628. X    -i: Go to interactive mode. No mail is sent out and the text saved
  10629. X    in MAILFORWARD will be read by serverd.
  10630. X    -D: Turn debug on. A transaction of the last email sent out is kept
  10631. X        in the files HOMEDIR/sent and HOMEDIR/received. This assumes
  10632. X    use of the 'system' mail method.
  10633. X
  10634. X  EXIT CODES:
  10635. X    0: OK
  10636. X    1: Could not open or lock file
  10637. X    2: SIGINT signal
  10638. X    3: Command line option error
  10639. X    4: Syntax error in file
  10640. X    5: Could not spawn
  10641. X    6: Shutdown request
  10642. X    7: Restart request
  10643. X    8: Received system signal
  10644. X    9: Too many multiple recipients
  10645. X   10: Could not deliver mail
  10646. X   11: Malloc failed
  10647. X   12: Cannot fork
  10648. X   13: Socket connection problem
  10649. X   14: Semaphore error
  10650. X   15: Cannot setuid, setgid
  10651. X   16: Internal error
  10652. X
  10653. X  Approximate algorithm:
  10654. X  {
  10655. X    Place a lock so that no other programs will access the same files.
  10656. X    Lock SERVER_MAIL_FILE or BATCH_FILE so catmail can't append to it
  10657. X    Read the SERVER_MAIL_FILE or BATCH_FILE
  10658. X    Unlock the file
  10659. X
  10660. X    if new messages have arrived then {
  10661. X      For each message do {
  10662. X        If the message is sent by MAILER-DAEMON forward it to MANAGER
  10663. X        else {
  10664. X      if the person in not in the IGNORED file, then
  10665. X          scan each line of the body of the message and treat it as a
  10666. X          command with possible arguments. Reply to the sender for each such
  10667. X          request. If a request cannot be processed, send an error message to
  10668. X          the sender and ignore all subsequent requests.
  10669. X        }
  10670. X      }
  10671. X    }
  10672. X  }
  10673. X
  10674. X  Required files:
  10675. X    SUBSCRIBERS       <-- The list of subscribed people (diff. for each list)
  10676. X    ALIASES          <-- Aliases of email addresses of subscribers, news &
  10677. X                  peers.
  10678. X    PEERS          <-- A list of peers for a particular list (where appl.)
  10679. X    IGNORED           <-- The list of undesired people (one for the server
  10680. X              and one for each list)
  10681. X
  10682. X  Input files:
  10683. X    HEADERS           <-- Used for the 'statistics' request (see list.c)
  10684. X    SERVER_MAIL_FILE  <-- Where new messages go
  10685. X    BATCH_FILE          <-- Where requests are batched
  10686. X    MAIL_COPY         <-- Copy of this file (actual work file)
  10687. X    MSG_NO            <-- Read last message count
  10688. X    SUBSCRIBERS
  10689. X    IGNORED     
  10690. X
  10691. X  Output files:
  10692. X    SERVER_MBOX       <-- A log of all messages sent
  10693. X    SUBSCRIBERS       <-- After updating
  10694. X    OLD_SUBSCRIBERS   <-- Temporary
  10695. X    MSG_NO            <-- Write last message count
  10696. X    REPORT_SERVER     <-- Progress report
  10697. X    MAILFORWARD       <-- Completed message (with header and the
  10698. X                          the body of the message) to be forwarded
  10699. X
  10700. X  Format of the SUBSCRIBERS, PEERS and IGNORED files:
  10701. X    See comments for list.c
  10702. X
  10703. X*/
  10704. X
  10705. X#include <stdio.h>
  10706. X#include <sys/types.h>
  10707. X#ifdef SYSLOG
  10708. X# ifdef ultrix
  10709. X#  include <sys/syslog.h>
  10710. X# else
  10711. X#  include <syslog.h>
  10712. X# endif
  10713. X#endif
  10714. X#include <ctype.h>
  10715. X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
  10716. X  && !defined (sequent) && !defined (unknown_port)
  10717. X# include <malloc.h>
  10718. X#endif
  10719. X#include <string.h>
  10720. X#ifndef unknown_port
  10721. X# ifndef __NeXT__
  10722. X#  include <unistd.h>
  10723. X# else
  10724. X#  include <libc.h>
  10725. X# endif
  10726. X#endif
  10727. X#include <sys/stat.h>
  10728. X#include <fcntl.h>
  10729. X#include <signal.h>
  10730. X#include <math.h>
  10731. X#if !defined (stellar) && !defined (unknown_port)
  10732. X# include <time.h>
  10733. X#endif
  10734. X#include <sys/time.h>
  10735. X#if !defined (sequent) && !defined (__NeXT__) && !defined (__convex__) && \
  10736. X !defined (apollo) && !defined (i386) && !defined (unknown_port)
  10737. X# include <sys/termio.h>
  10738. X#endif
  10739. X#ifndef sun
  10740. X# include <sys/ioctl.h>
  10741. X#endif
  10742. X#include <errno.h>
  10743. X#ifdef unknown_port
  10744. Xextern int errno;
  10745. X#endif
  10746. X#include "defs.h"
  10747. X#include "listproc.h"
  10748. X#include "struct.h"
  10749. X#include "global.h"
  10750. X#include "ilpp.h"
  10751. X#if defined (__NeXT__) || defined (unknown_port)
  10752. X# include "next.h"
  10753. X#endif
  10754. X
  10755. X#ifdef TCP_IP
  10756. X# include <sys/socket.h>
  10757. X# include <netdb.h>
  10758. X# include <netinet/in.h>
  10759. Xstruct     in_addr localaddr;
  10760. X#else
  10761. Xchar     *localaddr;
  10762. X#endif
  10763. X
  10764. X#ifdef GO_INTERACTIVE
  10765. X# include <sys/ipc.h>
  10766. X# include <sys/sem.h>
  10767. X#endif
  10768. X
  10769. X/* 
  10770. X  Function prototypes:
  10771. X*/
  10772. X
  10773. X#ifdef __STDC__
  10774. X# include "ansi/misc.h"
  10775. X# include <stdarg.h>
  10776. Xextern int  syscom (char *, ...);
  10777. Xextern int  silp (char *, int, char *, char *, int, char *, char *, ...);
  10778. Xextern char *tsprintf (char *, ...);
  10779. X#else
  10780. X# include "nonansi/misc.h"
  10781. X# include <varargs.h>
  10782. Xextern int  syscom ();
  10783. Xextern int  silp ();
  10784. Xextern char *tsprintf ();
  10785. X#endif
  10786. Xextern int  sys_config (FILE *, SYS *);
  10787. Xextern void report_progress (FILE *, char *, int);
  10788. Xextern void init_signals (void);
  10789. Xextern void catch_signals (void);
  10790. Xextern void setup_string (char *, char *, char *);
  10791. Xextern char *upcase (char *);
  10792. Xextern char *locase (char *);
  10793. Xextern void distribute (FILE *, void (*)(char *, char *, BOOLEAN),
  10794. X            FILE *, char *, char *, char *, char *, BOOLEAN);
  10795. Xextern char *clean_name (char *);
  10796. Xextern void clean_request (char *);
  10797. Xextern int  _getopt (int, char **, char *);
  10798. Xextern void get_list_name (char *, char *);
  10799. Xextern int  get_list_id (char *, SYS *, int);
  10800. Xextern void shrink (char *);
  10801. Xextern void free_remote (REMOTE **);
  10802. Xextern void check_aliases (char *, char *);
  10803. Xextern void shadow_password (char *);
  10804. Xextern void read_params (char *, char *, char *, FILE *, FILE *);
  10805. Xextern BOOLEAN extract_subscriber (FILE *, char *, BOOLEAN);
  10806. Xextern BOOLEAN extract_sender (char *);
  10807. Xextern BOOLEAN sysmail (char *);
  10808. Xextern BOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *,
  10809. X               BOOLEAN);
  10810. Xextern BOOLEAN strinstr (char *, char *);
  10811. Xextern BOOLEAN ignore_sender (FILE *, char *, FILE *, BOOLEAN);
  10812. Xextern BOOLEAN requested_part (char *, int);
  10813. Xextern BOOLEAN owner_listed (char *, char *, char *, FILE *);
  10814. Xextern BOOLEAN remove_msg (char *, int, FILE *);
  10815. Xextern int  lock_file (char *, int, int, BOOLEAN);
  10816. Xextern void unlock_file (int);
  10817. Xextern void escape_address (char *);
  10818. Xextern int  otoi (char *);
  10819. Xextern int  insert_word (char *, char **, int, int, int);
  10820. Xextern char *_strstr (char *, char *);
  10821. Xextern int  re_strcmp (char *, char *, char *);
  10822. Xextern char *mystrdup (char *);
  10823. Xextern int echo (char *, char *);
  10824. Xextern int echo_append (char *, char *);
  10825. Xextern int mv (char *, char *);
  10826. Xextern int cp (char *, char *);
  10827. Xextern int cat_append (char *, char *);
  10828. Xextern int touch (char *);
  10829. Xextern int ucb_strftime (char *, int, char *, struct tm *);
  10830. Xextern long int write_to_fd (int, char *, long int);
  10831. Xextern int P (int, int);
  10832. Xextern int V (int, int);
  10833. Xextern void escape_re (char *);
  10834. X
  10835. Xvoid   main (int, char **, char **);
  10836. Xvoid   process_message (char *, char *, BOOLEAN);
  10837. Xvoid   action (char *, char *, char *, BOOLEAN);
  10838. Xvoid   reply_code (int);
  10839. Xvoid   create_header (FILE **, char *, char *, char *, char *, BOOLEAN, int,
  10840. X              BOOLEAN, BOOLEAN);
  10841. Xvoid   reject_mail (char *, char *, char *, int, int);
  10842. Xvoid   System (char *, char *, char *);
  10843. Xvoid   get_sys_files (char *, char *, char *);
  10844. Xvoid   put (char *, char *, char *);
  10845. Xvoid   help (char *, char *, char *);
  10846. Xvoid   unsubscribe (char *, char *, char *);
  10847. Xvoid   subscribe (char *, char *, char *, BOOLEAN);
  10848. Xvoid   which (char *, char *, char *);
  10849. Xvoid   set (char *, char *, char *);
  10850. Xvoid   recipients (char *, char *, char *);
  10851. Xvoid   info (char *, char *, char *);
  10852. Xvoid   stats (char *, char *, char *);
  10853. Xvoid   Shutdown (char *, char *, char *);
  10854. Xvoid   restart (char *, char *, char *);
  10855. Xvoid   lists (char *, char *, char *);
  10856. Xvoid   Index (char *, char *, char *);
  10857. Xvoid   get (char *, char *, char *);
  10858. Xvoid   search (char *, char *, char *);
  10859. Xvoid   release (char *, char *, char *);
  10860. Xvoid   notify (char *, char *, char *);
  10861. Xvoid   approve (char *, char *, char *);
  10862. Xvoid   discard (char *, char *, char *);
  10863. Xvoid   notify_peer_servers (char *, char *, char *, char *);
  10864. Xvoid   execute (char *, char *, char *);
  10865. Xvoid   unix_cmd (char *, char *, char *);
  10866. Xvoid   init_commands (void);
  10867. Xvoid   usage (void);
  10868. Xvoid   server_config (char *);
  10869. Xint    gexit (int);
  10870. X
  10871. X/*
  10872. X  The control structure of the server. Check if mail has arrived.
  10873. X  If so, copy it to MAIL_COPY and proceed to lower level.
  10874. X  First, the command line options are analyzed (for restrictions, etc.).
  10875. X*/
  10876. X
  10877. Xvoid main (int argc, char **argv, char **envp)
  10878. X{
  10879. X  struct stat stat_buf;
  10880. X  char *options = "1r:d:enDa:b:c:BiS:F:R:C:", *mask;
  10881. X  int c;
  10882. X  BOOLEAN execute_once = FALSE, notok;
  10883. X  int i, j, k, rlfd = 2;
  10884. X  FILE *f;
  10885. X  extern char *optarg, *getenv();
  10886. X  extern int optopt;
  10887. X#ifdef TCP_IP
  10888. X  struct hostent *lhost;
  10889. X#endif
  10890. X
  10891. X  prog = argv[0];
  10892. X  init_commands();
  10893. X#ifdef SYSLOG
  10894. X  openlog ("ListProcessor: listproc", LOG_NDELAY
  10895. X# ifndef i386
  10896. X       |LOG_NOWAIT
  10897. X# endif
  10898. X       , SYSLOG);
  10899. X# ifndef ultrix
  10900. X  setlogmask (LOG_UPTO (LOG_INFO));
  10901. X# endif
  10902. X#else
  10903. X  if ((report = fopen (REPORT_SERVER, "a")) == NULL)
  10904. X    fprintf (stderr, "listproc: Unable to open %s\n", REPORT_SERVER),
  10905. X    exit (1);
  10906. X  chmod (REPORT_SERVER, 384); /* 600 */
  10907. X#endif
  10908. X  nlists = sys_config (report, &sys);
  10909. X  mailforwardf = MAILFORWARD;
  10910. X  replyf = ULISTPROCESSOR_REPLY;
  10911. X  RESET (requests_file);
  10912. X  while ((c = _getopt (argc, argv, options)) != EOF)
  10913. X    switch ((char) c) {
  10914. X      case '1': execute_once = TRUE; break;
  10915. X      case 'e': tty_echo = TRUE; break;
  10916. X      case 'i': interactive = TRUE;
  10917. X      case 'n': do_not_notify_peer_server = TRUE; break;
  10918. X      case 'S': sid = atoi (optarg); break;
  10919. X      case 'F': mailforwardf = mystrdup (optarg); break;
  10920. X      case 'R': strcpy (requests_file, optarg); break;
  10921. X      case 'C': replyf = mystrdup (optarg); break;
  10922. X      case 'a':
  10923. X      case 'c':
  10924. X    if ((listid = get_list_id (upcase (optarg), &sys, nlists)) < 0)
  10925. X      fprintf (stderr, "\nlistproc: Unknown list %s for -%c option\n",
  10926. X           optarg, c),
  10927. X      exit (3);
  10928. X    if (c == 'a')
  10929. X      sys.lists[listid].options |= NON_AUTO_SUB;
  10930. X    else if (c == 'c')
  10931. X      sys.lists[listid].options |= CONCEAL_LIST;
  10932. X    break;
  10933. X      case 'B': process_batch = TRUE; break;
  10934. X      case 'D': debug = TRUE; break;
  10935. X      case 'b':
  10936. X      case 'r':
  10937. X      case 'd':
  10938. X        notok = TRUE;
  10939. X        k = 0;
  10940. X        upcase (optarg);
  10941. X        for (i = 0; i < MAX_COMMANDS; ++i) {
  10942. X          notok &= (((j = strncmp (optarg, commands[i].name, strlen (optarg)))
  10943. X                    != 0) ? 1 : 0);
  10944. X          if (!j) {
  10945. X            ++k;
  10946. X        if (c == 'r')
  10947. X              restricted_commands |= commands[i].mask;
  10948. X        else if (c == 'd')
  10949. X          disabled_commands |= commands[i].mask;
  10950. X        else if (c == 'b')
  10951. X          batched_commands |= commands[i].mask;
  10952. X      }
  10953. X    }
  10954. X        if (notok)
  10955. X          fprintf (stderr, "listproc: Unrecognized request '%s'\n", optarg),
  10956. X          exit (3);
  10957. X        if (k > 1) /* ambiguous command */
  10958. X          fprintf (stderr, "listproc: Ambiguous request '%s'\n", optarg),
  10959. X          exit (3);
  10960. X        break;
  10961. X      case ':':
  10962. X          fprintf (stderr, "listproc: Option '%c' requires an argument.\n",
  10963. X           optopt);
  10964. X          exit (3);
  10965. X      case '?':
  10966. X      default:
  10967. X        usage ();
  10968. X    }
  10969. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  10970. X    umask (otoi (mask));
  10971. X  else
  10972. X    mask = "066",
  10973. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  10974. X  if (!execute_once)
  10975. X    printf ("%s", COPYRIGHT);
  10976. X  init_signals();
  10977. X  catch_signals();
  10978. X  if (sys.options & USE_ENV_VAR) {
  10979. X    if ((sys.mail.method = (char *) malloc (256 * sizeof (char))) == NULL)
  10980. X      report_progress (report, "\nmain(): malloc() failed", TRUE),
  10981. X      gexit (11);
  10982. X    sprintf (sys.mail.method, "env - %s=%s %s ", sys.mail.env_var,
  10983. X         sys.server.address, sys.mail.mail_prog);
  10984. X   }
  10985. X
  10986. X  if (!tty_echo) {
  10987. X    j = -1;
  10988. X#if defined (TIOCNOTTY) && defined (SIGTTOU) && defined (SIGTTIN)
  10989. X    if ((i = open ("/dev/tty", 2)) >= 0)
  10990. X      j = ioctl (i, TIOCNOTTY, 0),
  10991. X      close (i);
  10992. X#endif
  10993. X    if (j < 0 && 
  10994. X#ifdef svr4
  10995. X    setsid ()
  10996. X#else
  10997. X# ifdef SETPGRP_NEEDS_ARGS
  10998. X    setpgrp (0, 0) 
  10999. X# else
  11000. X    setpgrp ()
  11001. X# endif
  11002. X#endif 
  11003. X    < 0)
  11004. X      report_progress (report, "WARNING: could not detach from tty", TRUE);
  11005. X  }
  11006. X
  11007. X  if ((f = fopen (tsprintf ("%s.%d", PID_SERVER, getpid()), "w")) != NULL)
  11008. X    fprintf (f, "%d", getpid()),
  11009. X    fclose (f);
  11010. X  signal (SIGINT, (void (*) ()) gexit);
  11011. X  signal (SIGALRM, SIG_IGN);
  11012. X#ifdef TCP_IP
  11013. X  if (gethostname (hostname, sizeof (hostname)))
  11014. X    report_progress (report, tsprintf ("\nmain(): gethostname() failed: errno \
  11015. X%d", errno), TRUE),
  11016. X    gexit (16);
  11017. X  if (!(lhost = gethostbyname (hostname)))
  11018. X    report_progress (report, tsprintf ("\nmain(): gethostbyname() failed: errno %d", errno), TRUE),
  11019. X    gexit (16);
  11020. X  memcpy ((char *) &localaddr, (char *) lhost->h_addr, lhost->h_length);
  11021. X#else
  11022. X  localaddr = LOCAL_ADDR;
  11023. X  strcpy (hostname, HOSTNAME);
  11024. X#endif
  11025. X
  11026. X  if (process_batch) /* Select file to process: batch or requests */
  11027. X    strcpy (requests_file, BATCH_FILE);
  11028. X  else if (!interactive)
  11029. X    strcpy (requests_file, SERVER_MAIL_FILE);
  11030. X
  11031. X#ifdef GO_INTERACTIVE
  11032. X  if (requests_file[0] == EOS)
  11033. X    fprintf (stderr, "\nmain(): -R option required\n"),
  11034. X    gexit (3);
  11035. X#endif
  11036. X
  11037. X  do {
  11038. X    if (!stat (requests_file, &stat_buf) && stat_buf.st_size > 0) {
  11039. X#ifndef NO_LOCKS
  11040. X      if ((rlfd = lock_file (requests_file, O_RDWR, 0, FALSE)) < 0)
  11041. X    report_progress (report, tsprintf ("\nmain(): Cannot open or lock %s",
  11042. X                       requests_file), TRUE),
  11043. X    gexit (1); /* Cannot lock file, so exit, regardless of execute_once */
  11044. X#endif
  11045. X#ifdef GO_INTERACTIVE
  11046. X      IN_CRITICAL_SECTION ("main", SEM_SYSFILES);
  11047. X#endif
  11048. X      if (!interactive)
  11049. X    cp (requests_file, MAIL_COPY);
  11050. X      if (!process_batch)
  11051. X        cat_append (requests_file, SERVER_MBOX),
  11052. X        echo_append ("", SERVER_MBOX);
  11053. X#ifdef GO_INTERACTIVE
  11054. X      OUT_OF_CRITICAL_SECTION ("main", SEM_SYSFILES);
  11055. X#endif
  11056. X      if (!interactive && !unlink (requests_file))
  11057. X    touch (requests_file), /* rewrite file */
  11058. X    chmod (requests_file, /*384*/ 0666 & (0666 ^ otoi (mask)));
  11059. X#ifndef NO_LOCKS
  11060. X      unlock_file (rlfd);
  11061. X#endif
  11062. X      OPEN_FILE (mail, (!interactive ? MAIL_COPY : requests_file), "r", "main");
  11063. X      if (process_batch)
  11064. X    report_progress (report, PROCESSING_BATCH, FALSE);
  11065. X      else
  11066. X        report_progress (report, NEW_ARRIVAL, FALSE);
  11067. X      distribute (mail, (void (*)(char *, char *, BOOLEAN)) process_message,
  11068. X          report, NULL, NULL, NULL, NULL, TRUE);
  11069. X      fclose (mail);  /* Done */
  11070. X      shrink (message_idsf);
  11071. X      if (!interactive)
  11072. X    unlink (MAIL_COPY);  /* Done delivering */
  11073. X    }
  11074. X    else if (!execute_once) /* No mail to deliver */
  11075. X      if (sys.frequency > 0)
  11076. X        sleep (sys.frequency);
  11077. X  } while (!execute_once);
  11078. X#ifdef SYSLOG
  11079. X  closelog ();
  11080. X#else
  11081. X  fclose (report);
  11082. X#endif
  11083. X  free_remote (&rlists);
  11084. X  if (restart_sys)
  11085. X    gexit (7); /* Exit status of 7 signifies a restart request */
  11086. X  gexit (0);
  11087. X}
  11088. X
  11089. X/*
  11090. X  Process each message. Isolate each command and pass it to action().
  11091. X  Before that, check if the message is from MAILER_DAEMON, in which case
  11092. X  forward the message to MANAGER. Any messages from people listed in the
  11093. X  IGNORED file are not processed.
  11094. X  Note: Please look at the documentation for list.c for the definition of a
  11095. X  mailer daemon.
  11096. X*/
  11097. X
  11098. Xvoid process_message (char *sender, char *linecopy, BOOLEAN address_ok)
  11099. X{
  11100. X  char line [MAX_LINE];          /* ... from the current message */
  11101. X  char _line [MAX_LINE];
  11102. X  char request [MAX_LINE];       /* holds each command */
  11103. X  char sender_copy [MAX_LINE];
  11104. X  char senders_subject [MAX_LINE];
  11105. X  char id_copy [MAX_LINE];
  11106. X  char original_sender [MAX_LINE];
  11107. X  char received [MAX_LINE];
  11108. X  char precedence [MAX_LINE];       /* Holds the Precedence: */
  11109. X  char match [MAX_LINE];
  11110. X  char error [MAX_LINE];
  11111. X  char *at = NULL;
  11112. X  FILE *f;
  11113. X  BOOLEAN loop = FALSE;
  11114. X  BOOLEAN did_action;
  11115. X  BOOLEAN done;
  11116. X  BOOLEAN fake_mail = TRUE;
  11117. X  BOOLEAN mailer_daemon;
  11118. X  BOOLEAN susp_subject;
  11119. X  long int offset;
  11120. X
  11121. X  listid = -1;
  11122. X  peer_server_request = FALSE;
  11123. X  line[0] = message_id[0] = id_copy[0] = precedence[0] = received[0] = 
  11124. X    original_sender[0] = senders_subject[0] = RESET (sender_copy);
  11125. X  strcpy (sender_copy, sender);  /* We do not like converting the actual */
  11126. X  upcase (sender_copy);          /* address to upper case */
  11127. X#ifdef GO_INTERACTIVE
  11128. X  IN_CRITICAL_SECTION ("process_message", SEM_REQ_ID);
  11129. X#endif
  11130. X  if ((msg_no = fopen (MSG_NO, "r")) != NULL)
  11131. X    fscanf (msg_no, "%d\n", &request_no),
  11132. X    fclose (msg_no);
  11133. X  report_progress (report, tsprintf ("Request #%04d:%s\n", ++request_no,
  11134. X    (*sender != EOS ? sender : "\"\"")), FALSE);
  11135. X  OPEN_FILE (msg_no, MSG_NO, "w", "process_message");
  11136. X  fprintf (msg_no, "%d\n", request_no);
  11137. X  fclose (msg_no);
  11138. X#ifdef GO_INTERACTIVE
  11139. X  OUT_OF_CRITICAL_SECTION ("process_message", SEM_REQ_ID);
  11140. X#endif
  11141. X
  11142. X  while (!feof (mail) && line[0] != '\n') { /* Skip to beginning of message */
  11143. X    strcpy (match, "\\1");
  11144. X    if (re_strcmp (SUBJECT, line, match) > 0) {
  11145. X      strcpy (senders_subject, line + strlen (match));
  11146. X      sprintf (line, "%s", line + strlen (match));
  11147. X      strcpy (match, "\\1");
  11148. X      if (re_strcmp (PEER_SERVER_REQUEST, line, match) > 0)
  11149. X    peer_server_request = TRUE;
  11150. X    }
  11151. X    else if (re_strcmp (FROM, line, match) > 0)
  11152. X      strcpy (original_sender, line + strlen (match)), /* Save From: */
  11153. X      original_sender [strlen (original_sender) - 1] = EOS; /* \n -> \0 */
  11154. X    else if (re_strcmp (RECEIVED, line, match) > 0) { /* Check for fake mail */
  11155. X      strcpy (received, line + strlen (match));
  11156. X      received [strlen (received) - 1] = EOS;
  11157. X      sscanf (received, "%s %s", error, received); /* Get host after "from" */
  11158. X      upcase (received);  /* Relay host */
  11159. X      if (fake_mail && (at = strchr (sender_copy, '@')))
  11160. X    if (re_strcmp (at + 1, received, NULL) > 0)
  11161. X      fake_mail = FALSE;
  11162. X    } 
  11163. X    else if (re_strcmp (PRECEDENCE, line, match) > 0)
  11164. X      strcpy (precedence, line + strlen (match)), /* Remove "Precedence: " */
  11165. X      precedence [strlen (precedence) - 1] = EOS,
  11166. X      upcase (precedence);
  11167. X    else if (re_strcmp (MESSAGE_ID1, line, NULL) > 0 ||
  11168. X         re_strcmp (MESSAGE_ID2, line, NULL) > 0 ||
  11169. X         re_strcmp (MESSAGE_ID3, line, NULL) > 0)
  11170. X      strcpy (message_id, line + strlen ("Message-") + 4),
  11171. X      message_id [strlen (message_id) - 1] = EOS, /* \n -> \0 */
  11172. X      strcpy (id_copy, message_id);
  11173. X      upcase (id_copy);
  11174. X    RESET (line);
  11175. X    fgets (line, MAX_LINE - 2, mail);
  11176. X  }
  11177. X
  11178. X  offset = ftell (mail);
  11179. X#ifdef GO_INTERACTIVE
  11180. X  IN_CRITICAL_SECTION ("process_message", SEM_SYSFILES);
  11181. X#endif
  11182. X  if (re_strcmp (LOW_PRECEDENCES, precedence, NULL) > 0) {
  11183. X    NOTIFY_MANAGER_OF_MSG_IGNORED ("Low Precedence: %s message ignored.",
  11184. X                   precedence, "process_message");
  11185. X    loop = TRUE;
  11186. X  }
  11187. X  SETUP_MESSAGE_IDSF;
  11188. X  if (message_id[0] != EOS) { /* Check for mail loop using Message-Id: */
  11189. X    if (message_ids = fopen (message_idsf, "r")) {
  11190. X      if (ignore_sender (message_ids, id_copy, report, TRUE)) {
  11191. X    NOTIFY_MANAGER_OF_MSG_IGNORED ("The Message-Id: %s matches entries\n\
  11192. Xin the .message.ids file.", id_copy, "process_message");
  11193. X        loop = TRUE;
  11194. X      }
  11195. X      fclose (message_ids);
  11196. X    }
  11197. X    if (!loop) {
  11198. X      OPEN_FILE (message_ids, message_idsf, "a", "process_message");
  11199. X      fprintf (message_ids, "%s %s\n", message_id, sender); /* Save new id */
  11200. X      fclose (message_ids);
  11201. X    }
  11202. X  }
  11203. X  /* Check for mail loop using Message-Id: and X-Listprocessor-Version: in
  11204. X     the body */
  11205. X  while (!feof (mail) && 
  11206. X     (strncmp (_line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
  11207. X    RESET (_line);
  11208. X    fgets (_line, MAX_LINE - 2, mail);
  11209. X    if (re_strcmp (MESSAGE_ID1, _line, NULL) > 0 ||
  11210. X    re_strcmp (MESSAGE_ID2, _line, NULL) > 0 ||
  11211. X    re_strcmp (MESSAGE_ID3, _line, NULL) > 0) {
  11212. X      strcpy (id_copy, _line + strlen ("Message-") + 4);
  11213. X      id_copy [strlen (id_copy) - 1] = EOS; /* \n -> \0 */
  11214. X      upcase (id_copy);
  11215. X      if (message_ids = fopen (message_idsf, "r")) {
  11216. X    if (ignore_sender (message_ids, id_copy, report, TRUE)) {
  11217. X      NOTIFY_MANAGER_OF_MSG_IGNORED ("The Message-Id: %s matches entries\n\
  11218. Xin the .message.ids file.", id_copy, "process_message");
  11219. X      loop = TRUE;
  11220. X    }
  11221. X    fclose (message_ids);
  11222. X      }
  11223. X    }
  11224. X    else if (re_strcmp (LISTPROC_ID, _line, NULL) > 0)
  11225. X      report_progress (report, "Found X-Listprocessor-Version: id in message \
  11226. Xbody; message ignored", TRUE),
  11227. X      loop = TRUE;
  11228. X  }
  11229. X#ifdef GO_INTERACTIVE
  11230. X  OUT_OF_CRITICAL_SECTION ("process_message", SEM_SYSFILES);
  11231. X#endif
  11232. X  fseek (mail, offset, SEEK_SET);
  11233. X
  11234. X  if (!address_ok) {
  11235. X    RESET (request);
  11236. X    NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS (sender);
  11237. X    one_rejection = TRUE;
  11238. X  }
  11239. X
  11240. X  mailer_daemon = strinstr (MAILER_DAEMON, sender_copy) ||
  11241. X    (original_sender[0] != EOS && strinstr (MAILER_DAEMON, original_sender)) ||
  11242. X    *sender == EOS;
  11243. X  susp_subject = (senders_subject[0] != EOS &&
  11244. X          strinstr (SUSP_SUBJECT, senders_subject));
  11245. X  if (mailer_daemon || susp_subject) {
  11246. X    /* Send message to MANAGER */
  11247. X    create_header (&f, mailforwardf, sys.server.address, sys.manager,
  11248. X           senders_subject, FALSE, INVALID_REQ, TRUE, TRUE);
  11249. X    fprintf (f, "\nRejected message: sent to %s by %s follows.\n\
  11250. XReason for rejection: %s.\n--------------------------------------\
  11251. X-----------------------------------------\n", sys.server.address,
  11252. X         (*sender != EOS ? sender : "\"\""),
  11253. X         (mailer_daemon ? "suspicious address" :
  11254. X          (susp_subject ? "suspicious subject" : "???")));
  11255. X    RESET (line);
  11256. X    while (!feof (mail) && 
  11257. X           (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
  11258. X      fprintf (f, "%s", line);
  11259. X      RESET (line);
  11260. X      fgets (line, MAX_LINE - 2, mail);
  11261. X    }
  11262. X    COMPLETE_TELNET (f);
  11263. X    fclose (f);
  11264. X    DELIVER_MAIL (sys.manager, FALSE);
  11265. X    report_progress (report,
  11266. X             tsprintf ("Forwarding message to %s (%s)\n", sys.manager,
  11267. X                   (mailer_daemon ? "suspicious address" :
  11268. X                (susp_subject ? "suspicious subject" : "???"))),
  11269. X             FALSE);
  11270. X    did_action = TRUE;
  11271. X  }
  11272. X  else { /* Isolate request and call action() */
  11273. X    check_aliases (ALIASESF, sender);
  11274. X    done = did_action = FALSE;
  11275. X    if (!interactive && fake_mail && at && !one_rejection && !loop)
  11276. X      report_progress (report,
  11277. X               tsprintf ("*** Possible fake mail: Host %s in user \
  11278. Xaddress does\nnot match any of the domains in the Received: header lines.\n",
  11279. X                 at + 1), FALSE);
  11280. X    while (!feof (mail) && 
  11281. X           (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))) {
  11282. X      clean_request (line);
  11283. X      RESET (request);
  11284. X      sscanf (line, "%s ", request);
  11285. X      upcase (request);
  11286. X      if (!strcmp (request, START_OF_SIGNATURE) || strinstr (THANKS, request))
  11287. X    done = TRUE; /* End of requests, start of .signature */
  11288. X      else if (request[0] != EOS && !one_rejection && !loop && !done)
  11289. X    if (!re_strcmp ("[Oo][Ff][Ff][Ii][Cc][Ee][ \t]+[Mm][Ee][Mm][Oo]|\
  11290. XSubject|:[ \t]*.$|^\\>|^\\]|^\\||^#|^%|^\\}|^\\$", line, NULL))
  11291. X          action (line, request, sender, FALSE),
  11292. X      did_action = TRUE;
  11293. X      RESET (line);
  11294. X      fgets (line, MAX_LINE - 2, mail);
  11295. X    }
  11296. X  }
  11297. X  if (!did_action && !one_rejection && !loop) {
  11298. X    create_header (&f, mailforwardf, sys.server.address, sender,
  11299. X           "No requests found", FALSE, INVALID_REQ, FALSE, FALSE);
  11300. X    fprintf (f, "No requests found in your message. Requests should be \
  11301. Xincluded in the\nbody of the mail message.\n");
  11302. X    COMPLETE_TELNET (f);
  11303. X    fclose (f);
  11304. X    DELIVER_MAIL (sender, FALSE);
  11305. X  }
  11306. X  strcpy (linecopy, line);
  11307. X  one_rejection = FALSE;
  11308. X  report_progress (report, "", -TRUE); /* -TRUE for no leading newline */
  11309. X}
  11310. X
  11311. X/*
  11312. X  Recognize the 'request' and call the appropriate routine, or reject the
  11313. X  message if the request is not recognized. Isolate any parameters.
  11314. X  If a restriction is in force for the recognized request, then get
  11315. X  the number of users currently on the system and reject the request if
  11316. X  this number is greater that the predetermined threshold.
  11317. X  A request may be batched if we are not processing the batch queue and
  11318. X  the specified request is indeed to be batched according to the command
  11319. X  line options.
  11320. X*/
  11321. X
  11322. Xvoid action (char *line, char *request, char *sender, BOOLEAN override)
  11323. X{
  11324. X  char params [MAX_LINE];
  11325. X  char error [MAX_LINE];
  11326. X  char list_name [MAX_LINE];
  11327. X  char *users_file;
  11328. X  int i, nusers;
  11329. X  FILE *f, *ignored;
  11330. X#ifdef ultrix
  11331. X  time_t time_is = 0;
  11332. X#else
  11333. X  long int time_is = 0;
  11334. X#endif
  11335. X  struct tm *t;
  11336. X
  11337. X  report_progress (report, line, FALSE);
  11338. X  listid = -1;
  11339. X  RESET (error);
  11340. X  SETUP_IGNOREDF;
  11341. X  if ((ignored = fopen (server_ignoredf, "r"))) { /* No file for remote list */
  11342. X    if (ignore_sender (ignored, sender, report, FALSE)) {
  11343. X      NOTIFY_MANAGER_OF_MSG_IGNORED ("The sender's address (%s) matches \
  11344. Xentries\nin the .ignored file.", sender, "action");
  11345. X      fclose (ignored);
  11346. X      goto abort;
  11347. X    }
  11348. X    fclose (ignored);
  11349. X  }
  11350. X  upcase (sender);
  11351. X  original_params[0] = RESET (params);
  11352. X  read_params (line, params, request, mail, report);
  11353. X  strcpy (original_params, params); /* Preserve case */
  11354. X  upcase (params);
  11355. X  for (i = 0; i < MAX_COMMANDS; i++) /* Walk through the valid requests */
  11356. X    if (! strncmp (request, commands[i].name, strlen (request)) &&
  11357. X    strlen (request) > 2 && ! (disabled_commands & commands[i].mask)) {
  11358. X      if (strncmp (request, "SHUTDOWN", strlen (request)) &&
  11359. X          strncmp (request, "RESTART", strlen (request)) &&
  11360. X          strncmp (request, "LISTS", strlen (request)) &&
  11361. X      strncmp (request, "INDEX", strlen (request)) &&
  11362. X      strncmp (request, "GET", strlen (request)) &&
  11363. X      strncmp (request, "FAX", strlen (request)) &&
  11364. X      strncmp (request, "VIEW", strlen (request)) &&
  11365. X      strncmp (request, "SEARCH", strlen (request)) &&
  11366. X      strncmp (request, "RELEASE", strlen (request)) &&
  11367. X      strncmp (request, "WHICH", strlen (request)) &&
  11368. X      strncmp (request, "NOTIFY", strlen (request)) &&
  11369. X      strncmp (request, "EXECUTE", strlen (request)) &&
  11370. X          strncmp (request, "HELP", strlen (request))) {
  11371. X        get_list_name (params, list_name);
  11372. X        listid = get_list_id (list_name, &sys, nlists);
  11373. X        server_config (list_name);
  11374. X        if (listid < 0) {
  11375. X          if (list_name[0] == EOS)
  11376. X            sprintf (error, "%s: Missing list name\n\n\
  11377. XSyntax: %s <list> [...]\n", request, request);
  11378. X          else
  11379. X            sprintf (error, "%s: Unknown list name %s\n", request, list_name);
  11380. X          reject_mail (sender, line, error, SYNTAX_ERROR, REJECT_LIST);
  11381. X          return;
  11382. X        }
  11383. X        if ((ignored = fopen (ignoredf, "r"))) { /* No file for remote list */
  11384. X          if (ignore_sender (ignored, sender, report, FALSE)) {
  11385. X        NOTIFY_MANAGER_OF_MSG_IGNORED ("The sender's address (%s) matches \
  11386. Xentries\nin the .ignored file.", sender, "action");
  11387. X        fclose (ignored);
  11388. X            goto abort;
  11389. X      }
  11390. X      fclose (ignored);
  11391. X    }
  11392. X        if (commands[i].mask & sys.lists[listid].disabled_commands &&
  11393. X        !override) {
  11394. X      reject_mail (sender, line,
  11395. X               tsprintf ("%s requests for list %s are disabled\n",
  11396. X                 request, sys.lists[listid].alias),
  11397. X               INVALID_REQ, 0);
  11398. X      goto abort;
  11399. X    }
  11400. X      }
  11401. X      if (restricted_commands & commands[i].mask && !override) {
  11402. X    /* Restriction set */
  11403. X    syscom ("%s | %s \
  11404. X'{ \
  11405. X   for (i = 1; i < 20; i++) \
  11406. X     if ($i == \"users,\") \
  11407. X       print $(i-1);\
  11408. X}' > %s",
  11409. X        UPTIME, AWK, (users_file = mystrdup (tmpnam (NULL))));
  11410. X    OPEN_FILE (f, users_file, "r", "action");
  11411. X        fscanf (f, "%d", &nusers);
  11412. X        fclose (f);
  11413. X        unlink (users_file);
  11414. X    free ((char *) users_file);
  11415. X        if (nusers > sys.users) {
  11416. X          create_header (&f, mailforwardf, sys.server.address, sender, request,
  11417. X             FALSE, RESTRICTED_REQ, FALSE, FALSE);
  11418. X          fprintf (f, "This request takes a considerable amount of resources \
  11419. Xand certain restrictions\nare currently in force. Please resubmit your \
  11420. Xrequest at a later time.\n");
  11421. X      COMPLETE_TELNET (f);
  11422. X          fclose (f);
  11423. X      DELIVER_MAIL (sender, FALSE);
  11424. X          strcat (request, ": restriction enforced\n");
  11425. X          report_progress (report, request, FALSE);
  11426. X          goto abort;
  11427. X        }
  11428. X      }
  11429. X      if (!process_batch && 
  11430. X      (batched_commands & commands[i].mask)) { /* Batch request */
  11431. X    time (&time_is);
  11432. X    t = localtime (&time_is);
  11433. X    if (t->tm_hour >= sys.batch.start &&
  11434. X        t->tm_hour <= (sys.batch.stop - 1)) { /* Between 8am and 8pm */
  11435. X      if (interactive) { /* Cannot batch a "live" request */
  11436. X        OPEN_FILE (f, mailforwardf, "w", "action");
  11437. X        fprintf (f, ">%s\nThe request cannot be processed at this time: \
  11438. Xbatch mode in effect.\nPlease send email.\n", line);
  11439. X        fclose (f);
  11440. X        goto abort;
  11441. X      }
  11442. X      OPEN_FILE (f, BATCH_FILE, "a", "action");
  11443. X      time_is = time (0);
  11444. X      fprintf (f, "From %s %s\n\n%s\n", sender, ctime (&time_is), line);
  11445. X      fclose (f);
  11446. X      report_progress (report, "(request placed in the batch queue)\n",
  11447. X               FALSE);
  11448. X      goto abort;
  11449. X    }
  11450. X      }
  11451. X      commands[i].func (request, params, sender, override); /* Call routine */
  11452. X      goto abort;
  11453. X    }
  11454. X  if (! (sys.options & IGNR_INVLD_RQSTS) || interactive)
  11455. X    reject_mail (sender, line, tsprintf ("Unrecognized request %s\n", request),
  11456. X         INVALID_REQ, REJECT_REQUEST);
  11457. X  else
  11458. X    report_progress (report, "[ignored]\n", FALSE);
  11459. X  abort: ;
  11460. X}
  11461. X
  11462. X/*
  11463. X  Produce the reply code during a live session.
  11464. X*/
  11465. X
  11466. Xvoid reply_code (int reply)
  11467. X{
  11468. X  FILE *f;
  11469. X
  11470. X  OPEN_FILE (f, replyf, "w", "reply_code");
  11471. X  fprintf (f, "%d\n", reply);
  11472. X  fclose (f);
  11473. X}
  11474. X
  11475. X/*
  11476. X  Create a message header addressed to 'sender' with the given 'subject'.
  11477. X  If this a reply to an invalid request, 'copy_owner' should be TRUE.
  11478. X*/
  11479. X
  11480. Xvoid create_header (FILE **f, char *filename, char *sender, char *recipient, 
  11481. X            char *subject, BOOLEAN copy_owner, int reply,
  11482. X            BOOLEAN preserve_msg_id, BOOLEAN error_condition)
  11483. X{
  11484. X#ifdef NEED_DATE
  11485. X  char date [80];
  11486. X# ifdef ultrix
  11487. X  time_t time_is;
  11488. X# else
  11489. X  long int time_is;
  11490. X# endif
  11491. X  struct tm *t;
  11492. X#endif
  11493. X
  11494. X  if (interactive)
  11495. X    reply_code (reply);
  11496. X  OPEN_FILE (*f, filename, "w", "create_header");
  11497. X  locase (recipient);
  11498. X  if (subject [0] != EOS && subject [strlen (subject) - 1] == '\n')
  11499. X    subject [strlen (subject) - 1] = EOS;
  11500. X  if (interactive)
  11501. X    return;
  11502. X  if (!fax_it && sys.options & USE_TELNET) {
  11503. X    fprintf (*f, "HELO %s\nMAIL From: <%s>\nRCPT To: <%s>\n",
  11504. X#ifdef ZMAILER
  11505. X/*
  11506. X# ifdef TCP_IP
  11507. X         (char *) inet_ntoa (localaddr),
  11508. X# else
  11509. X         localaddr,
  11510. X# endif
  11511. X    Use either the local address or the host name.
  11512. X*/
  11513. X         hostname,
  11514. X#else
  11515. X         "",
  11516. X#endif
  11517. X         sender, recipient);
  11518. X    if (copy_owner)
  11519. X      fprintf (*f, "RCPT To: <%s>\n",
  11520. X           (listid >= 0 ? sys.lists[listid].owner : sys.manager));
  11521. X    fprintf (*f, "DATA\n");
  11522. X  }
  11523. X  if (preserve_msg_id && message_id[0] != EOS)
  11524. X    fprintf (*f, "Message-Id: %s\n", message_id);
  11525. X#ifdef NEED_DATE
  11526. X  time (&time_is);
  11527. X  t = localtime (&time_is);
  11528. X  ucb_strftime (date, 1024, "%a, %e %b %Y %T %Z", t);
  11529. X  fprintf (*f, "Date: %s\n", date);
  11530. X#endif
  11531. X#ifndef NO_ERRORS_TO
  11532. X  fprintf (*f, "Errors-To: %s\n",((listid < 0 || listid == nlists) ?
  11533. X                  sys.manager : sys.lists[listid].owner));
  11534. X#endif
  11535. X  fprintf (*f, "Reply-To: %s\nSender: %s\nFrom: %s\nTo: %s\n",
  11536. X       sender, sender, sender, recipient);
  11537. X  if (copy_owner && !fax_it)
  11538. X    fprintf (*f, "Cc: %s\n",
  11539. X         ((listid >= 0 && listid < nlists) ?
  11540. X          sys.lists[listid].owner : sys.manager));
  11541. X  fprintf (*f, "Subject: %s%s\nX-Listprocessor-Version: %s\n", 
  11542. X       (error_condition ? ERROR_CONDITION : ""), subject, VERSION);
  11543. X  if (sys.server.comment[0] != EOS)
  11544. X    fprintf (*f, "X-Comment: %s\n\n", sys.server.comment);
  11545. X  else
  11546. X    fprintf (*f, "\n");
  11547. X}
  11548. X
  11549. X/*
  11550. X  Send a message to 'sender' indicating an invalid request. The body of
  11551. X  the message is given in 'text'. Only one such mail is sent to the user
  11552. X  for each of his/her invalid requests. All subsequent requests are ignored.
  11553. X*/
  11554. X
  11555. Xvoid reject_mail (char *sender, char *request, char *text, int reply, int why)
  11556. X{
  11557. X  FILE *f;
  11558. X  char *newline;
  11559. X  if (one_rejection)
  11560. X    return;
  11561. X  one_rejection = TRUE;
  11562. X  create_header (&f, mailforwardf, sys.server.address, sender, 
  11563. X         "Invalid request", COPY_OWNER (ccerrors), reply, FALSE, TRUE);
  11564. X  fprintf (f, ">%s\n%s\n", request, text);
  11565. X  if ((newline = strchr (text, '\n')))
  11566. X    *(newline + 1) = EOS;
  11567. X  report_progress (report, text, FALSE);
  11568. X  if (interactive) {
  11569. X    fclose (f);
  11570. X    return;
  11571. X  }
  11572. X  fprintf (f, "Report any problems to '%s'.\nFor a list of the \
  11573. Xavailable requests send a message to %s\nwith a body consisting of nothing \
  11574. Xbut the word HELP\n\nPS: Any subsequent requests that you might have \
  11575. Xsubmitted have been ignored.\n",
  11576. X       ((listid < 0 || listid == nlists) ?
  11577. X        sys.manager : sys.lists[listid].owner),
  11578. X       sys.server.address);
  11579. X  COMPLETE_TELNET (f);
  11580. X  fclose (f);
  11581. X  DELIVER_MAIL (sender, COPY_OWNER (ccerrors));
  11582. X}
  11583. X
  11584. X/*
  11585. X  Execute a system request. This is usually a request issued by the
  11586. X  list's owner. System requests are valid only for the list the password
  11587. X  is given for.
  11588. X*/
  11589. X
  11590. Xvoid System (char *request, char *params, char *sender)
  11591. X{
  11592. X  char password [MAX_LINE];
  11593. X  char newrequest [MAX_LINE];
  11594. X  char newsender [MAX_LINE];
  11595. X  char list [MAX_LINE];
  11596. X  char *comment, *c;
  11597. X  int target_listid;
  11598. X  FILE *f;
  11599. X
  11600. X  newsender[0] = newrequest[0] = list[0] = RESET (password);
  11601. X  sscanf (params, "%s ", password);
  11602. X  if ((c = _strstr (params, password))) {
  11603. X    while (*c != EOS && !isspace (*c))  /* Get to the end of password */
  11604. X      ++c;
  11605. X    while (*c != EOS && isspace (*c))   /* Get to new sender address */
  11606. X      ++c;
  11607. X    sprintf (newsender, "From %s", c);
  11608. X    if (!extract_sender (newsender)) {  /* Error in address scanning */
  11609. X      shadow_password (params);
  11610. X      sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  11611. X           params);
  11612. X      NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS (newsender);
  11613. X      return;
  11614. X    }
  11615. X  }
  11616. X  shadow_password (params);
  11617. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  11618. X           params);
  11619. X  if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
  11620. X    NOT_LIST_OWNER; /* Hacker attack */
  11621. X    return;
  11622. X  }
  11623. X  if (password[0] == EOS) {
  11624. X    reject_mail (sender, request, "Missing password for SYSTEM request\n\n\
  11625. XSyntax: system <list> <password> <address> #<user-request>\n",
  11626. X         SYNTAX_ERROR, 0);
  11627. X    return;
  11628. X  }
  11629. X  if (password[0] == '#' || strcmp (password, sys.lists[listid].password)) {
  11630. X    reject_mail (sender, request, "Invalid password for SYSTEM request\n",
  11631. X         SYNTAX_ERROR, 0);
  11632. X    return;
  11633. X  }
  11634. X  if (newsender[0] == EOS || newsender[0] == '#') {
  11635. X    reject_mail (sender, request, "Missing user address for SYSTEM request\n\n\
  11636. XSyntax: system <list> <password> <address> #<user-request>\n",
  11637. X         SYNTAX_ERROR, 0);
  11638. X    return;
  11639. X  }
  11640. X  if (!(comment = strchr (params, '#'))) { /* No actual request */
  11641. X    reject_mail (sender, request, "Missing '#': no system request specified\n\n\
  11642. XSyntax: system <list> <password> <address> #<user-request>\n",
  11643. X         SYNTAX_ERROR, 0);
  11644. X    return;
  11645. X  }
  11646. X  sprintf (params, "%s", comment + 1); /* Remove password + sender address */
  11647. X  clean_request (params); /* Now we have the actual request */
  11648. X  sscanf (params, "%s %s", newrequest, list);
  11649. X  if (strlen (newrequest) < 3) {
  11650. X    reject_mail (sender, request, tsprintf ("Ambiguous request %s\n",
  11651. X                        newrequest), SYNTAX_ERROR, 0);
  11652. X    return;
  11653. X  }
  11654. X  if (strncmp (newrequest, "SHUTDOWN", strlen (newrequest)) &&
  11655. X      strncmp (newrequest, "RESTART", strlen (newrequest)) &&
  11656. X      strncmp (newrequest, "LISTS", strlen (newrequest)) &&
  11657. X      strncmp (newrequest, "SEARCH", strlen (newrequest)) &&
  11658. X      strncmp (newrequest, "INDEX", strlen (newrequest)) &&
  11659. X      strncmp (newrequest, "GET", strlen (newrequest)) &&
  11660. X      strncmp (newrequest, "FAX", strlen (newrequest)) &&
  11661. X      strncmp (newrequest, "VIEW", strlen (newrequest)) &&
  11662. X      strncmp (newrequest, "RELEASE", strlen (newrequest)) &&
  11663. X      strncmp (newrequest, "WHICH", strlen (newrequest)) &&
  11664. X      strncmp (newrequest, "NOTIFY", strlen (newrequest)) &&
  11665. X      strncmp (newrequest, "EXECUTE", strlen (newrequest)) &&
  11666. X      strncmp (newrequest, "HELP", strlen (newrequest)) &&
  11667. X      list[0] != EOS) { /* Check target list validity */
  11668. X    if ((target_listid = get_list_id (list, &sys, nlists)) < 0) {
  11669. X      reject_mail (sender, request, tsprintf ("Unknown list %s\n", list),
  11670. X           SYNTAX_ERROR, 0);
  11671. X      return;
  11672. X    }
  11673. X    if (listid != target_listid) { /* Owner is cheating */
  11674. X      reject_mail (sender, request,
  11675. X           tsprintf ("Invalid request for list %s; SYSTEM requests \
  11676. Xshould be made only\nfor list %s.\n",
  11677. X                 list, sys.lists[listid].alias), INVALID_REQ, 0);
  11678. X      return;
  11679. X    }
  11680. X  }
  11681. X  action (params, newrequest, newsender, TRUE);
  11682. X}
  11683. X
  11684. X/*
  11685. X  Provide the list owner with the requested files. The accumulated
  11686. X  report file is then shrunk. When a file is edited, the last modification
  11687. X  time is saved to prevent a subsequent put in case the file got modified
  11688. X  in the meantime.
  11689. X*/
  11690. X
  11691. Xvoid get_sys_files (char *request, char *params, char *sender)
  11692. X{
  11693. X  char password [MAX_LINE];
  11694. X  char req [MAX_LINE];
  11695. X  char file [MAX_LINE];
  11696. X  char extra [MAX_LINE];
  11697. X  FILE *f;
  11698. X  struct stat stat_buf;
  11699. X
  11700. X  req[0] = extra[0] = file[0] = RESET (password);
  11701. X  strcpy (req, request);
  11702. X  sscanf (params, "%s %s %s", password, file, extra);
  11703. X  shadow_password (params);
  11704. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  11705. X       params);
  11706. X  if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
  11707. X    NOT_LIST_OWNER; /* Hacker attack */
  11708. X    return;
  11709. X  }
  11710. X  if (password[0] == EOS) {
  11711. X    reject_mail (sender, request,
  11712. X         tsprintf ("Missing password for %s request\n\n%s\n", req,
  11713. X               (!strncmp (req, "EDIT", strlen (req)) ?
  11714. X                "Syntax: edit <list> <password> <file>\n\
  11715. X\tfile: subscribers/aliases/ignored/\
  11716. Xnews/peers/info/welcome" : "Syntax: reports <list> <password>")),
  11717. X         SYNTAX_ERROR, 0);
  11718. X    return;
  11719. X  }
  11720. X  if (strcmp (password, sys.lists[listid].password)) {
  11721. X    reject_mail (sender, request,
  11722. X         tsprintf ("Invalid password for %s request\n", req),
  11723. X         SYNTAX_ERROR, 0);
  11724. X    return;
  11725. X  }
  11726. X  if (!strncmp (req, "REPORTS", strlen (req))) { /* Send reports */
  11727. X    if (file[0] != EOS) {
  11728. X      reject_mail (sender, request,
  11729. X           tsprintf ("Too many arguments to REPORTS ... : %s\n\n\
  11730. XSyntax: reports <list> <password>\n", file), SYNTAX_ERROR, 0);
  11731. X      return;
  11732. X    }
  11733. X    create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  11734. X           OK, FALSE, FALSE);
  11735. X#ifndef SYSLOG
  11736. X    fprintf (f, "*** Here is the latest report file:\n\n");
  11737. X#else
  11738. X    fprintf (f, "Sorry, this system is using syslog(3) and no reports are \
  11739. Xavailable.\n");
  11740. X#endif
  11741. X    fclose (f);
  11742. X#ifndef SYSLOG
  11743. X    setup_string (report_listf, sys.lists[listid].alias, REPORT_LIST);
  11744. X    cat_append (report_listf, mailforwardf);
  11745. X#endif
  11746. X    APPEND_TELNET ("get_sys_files");
  11747. X    DELIVER_MAIL (sender, FALSE);
  11748. X#ifndef SYSLOG
  11749. X    if (!interactive)
  11750. X      create_header (&f, mailforwardf, sys.server.address, sender, request,
  11751. X             FALSE, OK, FALSE, FALSE);
  11752. X    else
  11753. X      OPEN_FILE (f, mailforwardf, "a", "get_sys_files");
  11754. X    fprintf (f, "*** Here is the accumulated report file; this file was shrunk \
  11755. Xafter it was sent\nto you, so you may wish to save it:\n\n");
  11756. X    fclose (f);
  11757. X    setup_string (report_listf, sys.lists[listid].alias, REPORT_LIST_ACC);
  11758. X    cat_append (report_listf, mailforwardf);
  11759. X    APPEND_TELNET ("get_sys_files");
  11760. X    DELIVER_MAIL (sender, FALSE);
  11761. X# ifdef GO_INTERACTIVE
  11762. X    IN_CRITICAL_SECTION ("get_sys_files", SEM_SYSFILES);
  11763. X# endif
  11764. X    shrink (report_listf);
  11765. X# ifdef GO_INTERACTIVE
  11766. X    OUT_OF_CRITICAL_SECTION ("get_sys_files", SEM_SYSFILES);
  11767. X# endif
  11768. X#endif
  11769. X  }
  11770. X  else { /* Request is EDIT */
  11771. X    if (extra[0] != EOS) {
  11772. X      reject_mail (sender, request,
  11773. X           tsprintf ("Too many arguments to EDIT ... %s: %s\n\n\
  11774. XSyntax: edit <list> <password> <file>\n\
  11775. X\tfile: subscribers/aliases/ignored/\
  11776. Xnews/peers/info/welcome\n", file, extra), SYNTAX_ERROR, 0);
  11777. X      return;
  11778. X    }
  11779. X    create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  11780. X           OK, FALSE, FALSE);
  11781. X# ifdef GO_INTERACTIVE
  11782. X    IN_CRITICAL_SECTION ("get_sys_files", SEM_LISTFILES);
  11783. X# endif
  11784. X    if (!strcmp (file, "ALIASES")) { /* Send .aliases */
  11785. X      fprintf (f, "*** Here is the aliases file:\n\n");
  11786. X      fclose (f);
  11787. X      cat_append (aliasesf, mailforwardf);
  11788. X      APPEND_TELNET ("get_sys_files");
  11789. X      DELIVER_MAIL (sender, FALSE);
  11790. X      PUT_TIMESTAMP (aliasesf, aliases_timestampf);
  11791. X    }
  11792. X    else if (!strcmp (file, "IGNORED")) { /* Send .ignored */
  11793. X      fprintf (f, "*** Here is the ignored file:\n\n");
  11794. X      fclose (f);
  11795. X      cat_append (ignoredf, mailforwardf);
  11796. X      APPEND_TELNET ("get_sys_files");
  11797. X      DELIVER_MAIL (sender, FALSE);
  11798. X      PUT_TIMESTAMP (ignoredf, ignored_timestampf);
  11799. X    }
  11800. X    else if (!strcmp (file, "INFO")) { /* Send .info */
  11801. X      fprintf (f, "*** Here is the info file:\n\n");
  11802. X      fclose (f);
  11803. X      cat_append (infof, mailforwardf);
  11804. X      APPEND_TELNET ("get_sys_files");
  11805. X      DELIVER_MAIL (sender, FALSE);
  11806. X      PUT_TIMESTAMP (infof, info_timestampf);
  11807. X    }
  11808. X    else if (!strcmp (file, "SUBSCRIBERS")) { /* Send .subscribers */
  11809. X      fprintf (f, "*** Here is the subscribers file:\n\n");
  11810. X      fclose (f);
  11811. X      cat_append (subscribersf, mailforwardf);
  11812. X      APPEND_TELNET ("get_sys_files");
  11813. X      DELIVER_MAIL (sender, FALSE);
  11814. X      PUT_TIMESTAMP (subscribersf, subscribers_timestampf);
  11815. X    }
  11816. X    else if (!strcmp (file, "WELCOME")) { /* Send .welcome */
  11817. X      fprintf (f, "*** Here is the welcome file:\n\n");
  11818. X      fclose (f);
  11819. X      cat_append (welcomef, mailforwardf);
  11820. X      APPEND_TELNET ("get_sys_files");
  11821. X      DELIVER_MAIL (sender, FALSE);
  11822. X      PUT_TIMESTAMP (welcomef, welcome_timestampf);
  11823. X    }
  11824. X    else if (!strcmp (file, "NEWS")) { /* Send .news */
  11825. X      fprintf (f, "*** Here is the news file:\n\n");
  11826. X      fclose (f);
  11827. X      cat_append (newsf, mailforwardf);
  11828. X      APPEND_TELNET ("get_sys_files");
  11829. X      DELIVER_MAIL (sender, FALSE);
  11830. X      PUT_TIMESTAMP (newsf, news_timestampf);
  11831. X    }
  11832. X    else if (!strcmp (file, "PEERS")) { /* Get .peers */
  11833. X      fprintf (f, "*** Here is the peers file:\n\n");
  11834. X      fclose (f);
  11835. X      cat_append (peersf, mailforwardf);
  11836. X      APPEND_TELNET ("get_sys_files");
  11837. X      DELIVER_MAIL (sender, FALSE);
  11838. X      PUT_TIMESTAMP (peersf, peers_timestampf);
  11839. X    }
  11840. X    else {
  11841. X      fprintf (f, "%s: No such file.\nFiles that can be obtained: \
  11842. Xsubscribers/aliases/ignored/news/peers/info/welcome\n", file);
  11843. X      COMPLETE_TELNET (f);
  11844. X      fclose (f);
  11845. X      DELIVER_MAIL (sender, FALSE);
  11846. X    }
  11847. X# ifdef GO_INTERACTIVE
  11848. X    OUT_OF_CRITICAL_SECTION ("get_sys_files", SEM_LISTFILES);
  11849. X# endif
  11850. X  }
  11851. X}
  11852. X
  11853. X/*
  11854. X  Perform various list owner requests: put user addresses in files, or
  11855. X  put new files in the list's directory. The owner may put new aliases
  11856. X  in the .aliases file, new users to be ignored in the .ignored file,
  11857. X  change the welcome message in .welcome, and change the informative
  11858. X  message in .info.
  11859. X*/
  11860. X
  11861. Xvoid put (char *request, char *params, char *sender)
  11862. X{
  11863. X  char password [MAX_LINE];
  11864. X  char keyword [MAX_LINE];
  11865. X  char arg1 [MAX_LINE];
  11866. X  char arg2 [MAX_LINE];
  11867. X  char arg3 [MAX_LINE];
  11868. X  char line [MAX_LINE];
  11869. X  char sign [MAX_LINE];
  11870. X  char params_copy [MAX_LINE];
  11871. X  BOOLEAN signature;
  11872. X  FILE *f;
  11873. X  struct stat stat_buf;
  11874. X  time_t timestamp;
  11875. X  long int sig_mask;
  11876. X
  11877. X  arg1[0] = arg2[0] = arg3[0] = keyword[0] = params_copy[0] = RESET (password);
  11878. X  sscanf (original_params, "%s %s %s %s %s %s", password, password, keyword,
  11879. X      arg1, arg2, arg3);    /* Actually only interested in arg[1-3] */
  11880. X  sscanf (params, "%s %s", password, keyword);
  11881. X  strcpy (params_copy, params);
  11882. X  shadow_password (params);
  11883. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  11884. X       params);
  11885. X  if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
  11886. X    NOT_LIST_OWNER; /* Hacker attack */
  11887. X    return;
  11888. X  }
  11889. X  if (password[0] == EOS) {
  11890. X    reject_mail (sender, request, "Missing password for PUT request\n\n\
  11891. XSyntax: put <list> <password> <keyword> [args]\n\
  11892. X\tkeyword:alias/ignore/subscribers/aliases/news/peers/ignored/info/welcome\n\
  11893. X\targs:email address for alias/ignore\n",
  11894. X         SYNTAX_ERROR, 0);
  11895. X    return;
  11896. X  }
  11897. X  if (strcmp (password, sys.lists[listid].password)) {
  11898. X    reject_mail (sender, request, "Invalid password for PUT request\n",
  11899. X         SYNTAX_ERROR, 0);
  11900. X    return;
  11901. X  }
  11902. X# ifdef GO_INTERACTIVE
  11903. X  IN_CRITICAL_SECTION ("get_sys_files", SEM_LISTFILES);
  11904. X# endif
  11905. X  if (!strcmp (keyword, "ALIAS")) { /* Add to list's, system's aliases files */
  11906. X    if (arg1[0] == EOS || arg2[0] == EOS || arg3[0] != EOS) {
  11907. X      reject_mail (sender, request, "Wrong number of arguments to \
  11908. XPUT ... ALIAS\n\n\
  11909. XSyntax: put <list> <password> alias <alias-address> <address-as-subscribed | \
  11910. Xregex>\n", SYNTAX_ERROR, 0);
  11911. X    }
  11912. X    else
  11913. X      echo_append (tsprintf ("%s %s", arg1, arg2), aliasesf),
  11914. X      echo_append (tsprintf ("%s %s", arg1, arg2), ALIASESF);
  11915. X  }
  11916. X  else if (!strcmp (keyword, "IGNORE")) { /* Add to list's ignore file */
  11917. X    if (arg1[0] == EOS || arg2[0] != EOS) {
  11918. X      reject_mail (sender, request, "Wrong number of arguments to \
  11919. XPUT ... IGNORE\n\n\
  11920. XSyntax: put <list> <password> ignore <address>\n", SYNTAX_ERROR, 0);
  11921. X    }
  11922. X    else
  11923. X      echo_append (tsprintf ("%s", arg1), ignoredf);
  11924. X  }
  11925. X  else if (!strcmp (keyword, "WELCOME") || !strcmp (keyword, "INFO") ||
  11926. X       !strcmp (keyword, "ALIASES") || !strcmp (keyword, "IGNORED") ||
  11927. X       !strcmp (keyword, "SUBSCRIBERS") || !strcmp (keyword, "NEWS") ||
  11928. X       !strcmp (keyword, "PEERS")) {
  11929. X    if (arg1[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
  11930. X      reject_mail (sender, request,
  11931. X           tsprintf ("Too many arguments to PUT ... %s: %s\n\n\
  11932. XSyntax: put <list> <password> <file>\n\
  11933. X\tfile: subscribers/aliases/news/peers/ignored/info/welcome\n", keyword, arg1),
  11934. X           SYNTAX_ERROR, 0);
  11935. X    }
  11936. X    else if (!strcmp (keyword, "WELCOME")) { /* Write to .welcome */
  11937. X      CHECK_TIMESTAMP (welcome_timestampf, welcomef);
  11938. X      OPEN_FILE (f, welcomef, "w", "put");
  11939. X      unlink (welcome_timestampf);
  11940. X    }
  11941. X    else if (!strcmp (keyword, "INFO")) { /* Write to .info */
  11942. X      CHECK_TIMESTAMP (info_timestampf, infof);
  11943. X      OPEN_FILE (f, infof, "w", "put");
  11944. X      unlink (info_timestampf);
  11945. X    }
  11946. X    else if (!strcmp (keyword, "ALIASES")) { /* Write to .aliases */
  11947. X      CHECK_TIMESTAMP (aliases_timestampf, aliasesf);
  11948. X      OPEN_FILE (f, aliasesf, "w", "put");
  11949. X      unlink (aliases_timestampf);
  11950. X    }
  11951. X    else if (!strcmp (keyword, "IGNORED")) { /* Wite to .ignored */
  11952. X      CHECK_TIMESTAMP (ignored_timestampf, ignoredf);
  11953. X      OPEN_FILE (f, ignoredf, "w", "put");
  11954. X      unlink (ignored_timestampf);
  11955. X    }
  11956. X    else if (!strcmp (keyword, "SUBSCRIBERS")) { /* Write to .subscribers */
  11957. X      CHECK_TIMESTAMP (subscribers_timestampf, subscribersf);
  11958. X      OPEN_FILE (f, subscribersf, "w", "put");
  11959. X      unlink (subscribers_timestampf);
  11960. X    }
  11961. X    else if (!strcmp (keyword, "NEWS")) { /* Write to .news */
  11962. X      CHECK_TIMESTAMP (news_timestampf, newsf);
  11963. X      OPEN_FILE (f, newsf, "w", "put");
  11964. X      unlink (news_timestampf);
  11965. X    }
  11966. X    else { /* Write to .peers */
  11967. X      CHECK_TIMESTAMP (peers_timestampf, peersf);
  11968. X      OPEN_FILE (f, peersf, "w", "put");
  11969. X      unlink (peers_timestampf);
  11970. X    }
  11971. X#ifdef bsd
  11972. X    sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  11973. X#elif defined (svr4) || defined (svr3)
  11974. X    sighold (SIGINT);
  11975. X    sighold (SIGTERM);
  11976. X#endif
  11977. X    fflush (f);
  11978. X    COPY_MESSAGE;
  11979. X    fclose (f);
  11980. X#ifdef bsd
  11981. X    sigsetmask (sig_mask);
  11982. X#elif defined (svr4) || defined (svr3)
  11983. X    sigrelse (SIGINT);
  11984. X    sigrelse (SIGTERM);
  11985. X#endif
  11986. X    fclose (f);
  11987. X  }
  11988. X  else {
  11989. X#ifdef GO_INTERACTIVE
  11990. X    OUT_OF_CRITICAL_SECTION ("put", SEM_LISTFILES);
  11991. X#endif
  11992. X    reject_mail (sender, request, "Invalid or missing keyword for PUT \
  11993. Xrequest\n\n\
  11994. XSyntax: put <list> <password> <keyword> [args]\n\
  11995. X\tkeyword:alias/ignore/subscribers/aliases/news/peers/ignored/info/welcome\n\
  11996. X\targs:email address for alias/ignore\n", SYNTAX_ERROR, 0);
  11997. X    return;
  11998. X  }
  11999. X#ifdef GO_INTERACTIVE
  12000. X  OUT_OF_CRITICAL_SECTION ("put", SEM_LISTFILES);
  12001. X#endif
  12002. X  if (!one_rejection) {
  12003. X    create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  12004. X           OK, FALSE, FALSE);
  12005. X    fprintf (f, "Your request was successfully completed.\n");
  12006. X    COMPLETE_TELNET (f);
  12007. X    fclose (f);
  12008. X    DELIVER_MAIL (sender, FALSE);
  12009. X  }
  12010. X}
  12011. X
  12012. X/*
  12013. X  Provide help on the specified topic to 'sender'.
  12014. X*/
  12015. X
  12016. Xvoid help (char *request, char *params, char *sender)
  12017. X{
  12018. X  FILE *f, *index;
  12019. X  char param [MAX_LINE];
  12020. X  char moreparams [MAX_LINE];
  12021. X  char topic [MAX_LINE];
  12022. X  char file [MAX_LINE];
  12023. X  char shell [MAX_LINE];
  12024. X  BOOLEAN found;
  12025. X  struct stat stat_buf;
  12026. X  int ntopics;
  12027. X
  12028. X  sprintf (request + strlen (request), "%s", params); /* Used as a subject */
  12029. X  param[0] = RESET (moreparams);
  12030. X  sscanf (params, "%s %s\n", param, moreparams);
  12031. X  if (moreparams[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
  12032. X    reject_mail (sender, request, tsprintf ("Too many HELP topics: %s\n\n\
  12033. XPlease separate them into multiple HELP requests.\n\n\
  12034. XSyntax: help [topic | request]\n", moreparams),
  12035. X         SYNTAX_ERROR, 0);
  12036. X    return;
  12037. X  }
  12038. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  12039. X         COPY_OWNER (cchelp), OK, FALSE, FALSE);
  12040. X  if (param[0] == EOS)
  12041. X    strcpy (param, "GENERAL");
  12042. X  found = FALSE;
  12043. X  if ((index = fopen (HELP_TOPICS, "r")) == NULL)
  12044. X    fprintf (f, "Sorry, no help index found.\n");
  12045. X  else {  /* Check index for help topic, get filename */
  12046. X    while (!feof (index)) {
  12047. X      topic[0] = RESET (file);
  12048. X      fscanf (index, "%s %s\n", topic, file);
  12049. X      upcase (topic);
  12050. X      if (topic[0] != EOS)
  12051. X    if (!strncmp (param, topic, strlen (param))) { /* A match */
  12052. X      found = TRUE;
  12053. X      break;
  12054. X    }
  12055. X    }
  12056. X    if (!found) {
  12057. X      fprintf (f, "Sorry, no help on topic '%s' currently available.\n\n\
  12058. XHelp is available on the following topics:\n\n", param);
  12059. X      rewind (index);
  12060. X      ntopics = 0;
  12061. X      while (!feof (index)) {
  12062. X    topic[0] = RESET (file);
  12063. X    fscanf (index, "%s %s\n", topic, file);
  12064. X    fprintf (f, "%s ", topic);
  12065. X    if ((++ntopics) > 9)
  12066. X      ntopics = 0,
  12067. X      fprintf (f, "\n");
  12068. X      }
  12069. X      fprintf (f, "\n");
  12070. X    }
  12071. X    else if (stat (file, &stat_buf))
  12072. X      fprintf (f, "Sorry, unable to stat file %s for topic '%s'.\n", file,
  12073. X           param),
  12074. X      found = FALSE;
  12075. X    fclose (index);
  12076. X  }
  12077. X  fclose (f);
  12078. X  if (found) {
  12079. X    strcpy (shell, "cat");
  12080. X    if ((f = fopen (file, "r"))) {
  12081. X      fgets (shell, 3, f);
  12082. X      if (!strncmp (shell, "#!", 2)) {
  12083. X    fgets (shell, MAX_LINE - 2, f);
  12084. X    if (shell [strlen (shell) - 1] == '\n')
  12085. X      shell [strlen (shell) - 1] = EOS;
  12086. X      }
  12087. X      else
  12088. X    strcpy (shell, "cat");
  12089. X      fclose (f);
  12090. X    }
  12091. X    syscom ("%s %s >> %s", shell, file, mailforwardf);
  12092. X  }
  12093. X  APPEND_TELNET ("help");
  12094. X  DELIVER_MAIL (sender, COPY_OWNER (cchelp));
  12095. X}
  12096. X
  12097. X/*
  12098. X  Unsubscribe a member if he/she is listed in SUBSCRIBERS. If the list
  12099. X  is remote, the request is forwarded.
  12100. X*/
  12101. X
  12102. Xvoid unsubscribe (char *request, char *params, char *sender)
  12103. X{
  12104. X  FILE *f;
  12105. X  char error [10240];
  12106. X  char param [MAX_LINE];
  12107. X  char sender_copy [MAX_LINE];
  12108. X  char address [MAX_LINE];
  12109. X  BOOLEAN status, ok_to_reset_address = FALSE, _interactive;
  12110. X  long int sig_mask;
  12111. X  int i;
  12112. X  
  12113. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  12114. X           params); /* Used as a subject */
  12115. X  if (matched_rlists) { /* Request for a remote list; notify sender */
  12116. X    NOTIFY_OF_REQUEST_FORWARDING;
  12117. X    FORWARD_REQUEST;
  12118. X    return;
  12119. X  }
  12120. X  error[0] = RESET (param);
  12121. X  sscanf (params, "%s", param);
  12122. X  if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
  12123. X    reject_mail (sender, request, tsprintf ("Invalid UNSUBSCRIBE option%s\n\
  12124. XSyntax: unsubscribe <list> (or signoff <list>)\n", params),
  12125. X         SYNTAX_ERROR, 0);
  12126. X    return;
  12127. X  }
  12128. X  if (!(status = subscribed (report, sender, subscribersf, newsf, peersf,
  12129. X                 aliasesf, TRUE))) {
  12130. X    if ((sys.lists[listid].defaults.set_values[0][0] == EOS &&
  12131. X     !strcmp (default_values [0], "VARIABLE")) ||
  12132. X    (!strcmp (sys.lists[listid].defaults.set_values[0], "VARIABLE")))
  12133. X      ok_to_reset_address = TRUE;
  12134. X    sprintf (error, "%s: You are not subscribed to %s\n", sender,
  12135. X             sys.lists[listid].address);
  12136. X    if (alternate_addresses) {
  12137. X      sprintf (error + strlen (error),
  12138. X           "\nIn addition, the system found the following \
  12139. Xaddress(es) that resemble yours.\nIf one of these is you, please resend your \
  12140. Xmessage from that one%s:\n\n",
  12141. X           (ok_to_reset_address ?
  12142. X        ", or use the\n'set <list> address' request to change the \
  12143. Xaddress you are subscribed with" :
  12144. X        ""));
  12145. X      for (i = 0; alternate_addresses[i]; ++i)
  12146. X    sprintf (error + strlen (error), "%s\n", alternate_addresses[i]),
  12147. X    free ((char *) alternate_addresses[i]);
  12148. X      free ((char **) alternate_addresses);
  12149. X      alternate_addresses = NULL;
  12150. X      strcat (error, "\n");
  12151. X    }
  12152. X    reject_mail (sender, request, error, INVALID_REQ, 0);
  12153. X    return;
  12154. X  }
  12155. X  else if (status > SUBSCRIBED) { /* Notify manager */
  12156. X    NOTIFY_MANAGER ("Attempt to unsubscribe news or peer");
  12157. X    return;
  12158. X  }
  12159. X  /* Now move the current list of subscribers to a temporary file; then
  12160. X     copy each entry of this file to SUBSCRIBERS excluding the
  12161. X     user to be removed. */
  12162. X#ifdef GO_INTERACTIVE
  12163. X  IN_CRITICAL_SECTION ("unsubscribe", SEM_LISTFILES);
  12164. X#endif
  12165. X  strcpy (sender_copy, sender);
  12166. X  escape_re (sender_copy);
  12167. X  sprintf (address, "^[\t ]*%s[ \t]", sender_copy);
  12168. X  upcase (address);
  12169. X  if (cp (subscribersf, OLD_SUBSCRIBERS))
  12170. X    gexit (16);
  12171. X  REMOVE_ADDRESS (address, OLD_SUBSCRIBERS, NEW_SUBSCRIBERS);
  12172. X#ifdef bsd
  12173. X  sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12174. X#elif defined (svr4) || defined (svr3)
  12175. X  sighold (SIGINT);
  12176. X  sighold (SIGTERM);
  12177. X#endif
  12178. X  if (mv (NEW_SUBSCRIBERS, subscribersf))
  12179. X    gexit (16);
  12180. X#ifdef bsd
  12181. X  sigsetmask (sig_mask);
  12182. X#elif defined (svr4) || defined (svr3)
  12183. X  sigrelse (SIGINT);
  12184. X  sigrelse (SIGTERM);
  12185. X#endif
  12186. X  if (cp (aliasesf, OLD_ALIASES))
  12187. X    gexit (16);
  12188. X  REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
  12189. X#ifdef bsd
  12190. X  sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12191. X#elif defined (svr4) || defined (svr3)
  12192. X  sighold (SIGINT);
  12193. X  sighold (SIGTERM);
  12194. X#endif
  12195. X  if (mv (NEW_ALIASES, aliasesf))
  12196. X    gexit (16);
  12197. X#ifdef bsd
  12198. X  sigsetmask (sig_mask);
  12199. X#elif defined (svr4) || defined (svr3)
  12200. X  sigrelse (SIGINT);
  12201. X  sigrelse (SIGTERM);
  12202. X#endif
  12203. X  if (cp (ALIASESF, OLD_ALIASES))
  12204. X    gexit (16);
  12205. X  REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
  12206. X#ifdef bsd
  12207. X  sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12208. X#elif defined (svr4) || defined (svr3)
  12209. X  sighold (SIGINT);
  12210. X  sighold (SIGTERM);
  12211. X#endif
  12212. X  if (mv (NEW_ALIASES, ALIASESF))
  12213. X#ifdef bsd
  12214. X  sigsetmask (sig_mask);
  12215. X#elif defined (svr4) || defined (svr3)
  12216. X  sigrelse (SIGINT);
  12217. X  sigrelse (SIGTERM);
  12218. X#endif
  12219. X  sprintf (address, "[ \t]%s[\t ]*$", sender_copy);
  12220. X  upcase (address);
  12221. X  if (cp (aliasesf, OLD_ALIASES))
  12222. X    gexit (16);
  12223. X  REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
  12224. X#ifdef bsd
  12225. X  sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12226. X#elif defined (svr4) || defined (svr3)
  12227. X  sighold (SIGINT);
  12228. X  sighold (SIGTERM);
  12229. X#endif
  12230. X  if (mv (NEW_ALIASES, aliasesf))
  12231. X    gexit (16);
  12232. X#ifdef bsd
  12233. X  sigsetmask (sig_mask);
  12234. X#elif defined (svr4) || defined (svr3)
  12235. X  sigrelse (SIGINT);
  12236. X  sigrelse (SIGTERM);
  12237. X#endif
  12238. X  if (cp (ALIASESF, OLD_ALIASES))
  12239. X    gexit (16);
  12240. X  REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
  12241. X#ifdef bsd
  12242. X  sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12243. X#elif defined (svr4) || defined (svr3)
  12244. X  sighold (SIGINT);
  12245. X  sighold (SIGTERM);
  12246. X#endif
  12247. X  if (mv (NEW_ALIASES, ALIASESF))
  12248. X    gexit (16);
  12249. X#ifdef bsd
  12250. X  sigsetmask (sig_mask);
  12251. X#elif defined (svr4) || defined (svr3)
  12252. X  sigrelse (SIGINT);
  12253. X  sigrelse (SIGTERM);
  12254. X#endif
  12255. X  unlink (OLD_SUBSCRIBERS);
  12256. X  unlink (OLD_ALIASES);
  12257. X#ifdef GO_INTERACTIVE
  12258. X  OUT_OF_CRITICAL_SECTION ("unsubscribe", SEM_LISTFILES);
  12259. X#endif
  12260. X  _interactive = interactive;
  12261. X  interactive = FALSE;    /* Force email to sender */
  12262. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  12263. X         COPY_OWNER (ccunsub), OK, FALSE, FALSE);
  12264. X  fprintf (f, "You have been removed from list %s.\n\
  12265. XThanks for being with us.\n", sys.lists[listid].address);
  12266. X  COMPLETE_TELNET (f);
  12267. X  fclose (f);
  12268. X  DELIVER_MAIL (sender, COPY_OWNER (ccunsub));
  12269. X  interactive = _interactive;
  12270. X  if (interactive) { /* Notify ilp client */
  12271. X    create_header (&f, mailforwardf, sys.server.address, sender, request,
  12272. X           COPY_OWNER (ccsub), OK, FALSE, FALSE);
  12273. X    fprintf (f, "User %s was successfully removed from list %s.\n", sender,
  12274. X         sys.lists[listid].address);
  12275. X    fclose (f);
  12276. X  }
  12277. X}
  12278. X
  12279. X/*
  12280. X  Subscribe a new user if he/she is not already subscribed. If the list
  12281. X  is remote, the request is forwarded. If the list is private, a message
  12282. X  is sent to the sender, and another one to the list owner requesting his
  12283. X  approval.
  12284. X*/
  12285. X
  12286. Xvoid subscribe (char *request, char *params, char *sender, BOOLEAN override)
  12287. X{
  12288. X  FILE *f;
  12289. X  char name [MAX_LINE];
  12290. X  char password [MAX_LINE];
  12291. X  char shell [MAX_LINE];
  12292. X  long int sig_mask;
  12293. X  int i;
  12294. X  BOOLEAN status;
  12295. X  BOOLEAN _interactive;
  12296. X  BOOLEAN live;
  12297. X  BOOLEAN chaddr;
  12298. X
  12299. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  12300. X           params); /* Used as a subject */
  12301. X  if (matched_rlists) { /* Request for a remote list; notify sender */
  12302. X    NOTIFY_OF_REQUEST_FORWARDING;
  12303. X    FORWARD_REQUEST;
  12304. X    return;
  12305. X  }
  12306. X  RESET (name);
  12307. X  clean_name (params); /* Remove extraneous characters */
  12308. X  sscanf (params, "%s\n", name);
  12309. X  if (name[0] == EOS) {  /* No user's name */
  12310. X    reject_mail (sender, request, "No name given to SUBSCRIBE\n\n\
  12311. XSyntax: subscribe <list> <Your Name>\n", SYNTAX_ERROR,
  12312. X         REJECT_NAME);
  12313. X    return;
  12314. X  }
  12315. X  if ((status = subscribed (report, sender, subscribersf, newsf, peersf,
  12316. X                aliasesf, TRUE)) == SUBSCRIBED) {
  12317. X    reject_mail (sender, request,
  12318. X         tsprintf ("%s: You are already subscribed to %s\n", sender, 
  12319. X               sys.lists[listid].address), INVALID_REQ, 0);
  12320. X    return;
  12321. X  }
  12322. X  else if (status > SUBSCRIBED) { /* Notify manager */
  12323. X    NOTIFY_MANAGER ("Attempt to subscribe news or peer");
  12324. X    return;
  12325. X  }
  12326. X  if ((sys.lists[listid].options & NON_AUTO_SUB) &&
  12327. X      !owner_listed (OWNERSF, sender, sys.lists[listid].alias, report) &&
  12328. X      !override) { /* Notify sender/owner */
  12329. X    create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  12330. X           RESTRICTED_REQ, FALSE, FALSE);
  12331. X    fprintf (f, "Subscription requests are not automatic for this list. \
  12332. XYour request has\nbeen forwarded to %s for approval.\n",
  12333. X         sys.lists[listid].owner);
  12334. X    COMPLETE_TELNET (f);
  12335. X    fclose (f);
  12336. X    DELIVER_MAIL (sender, FALSE);
  12337. X    create_header (&f, mailforwardf, sys.server.address, sys.lists[listid].owner,
  12338. X           "Subscription approval request", FALSE, OK, FALSE, FALSE);
  12339. X    fprintf (f, "User %s has requested subscription to list %s\n\
  12340. XIf you approve, send the following request to %s:\n\n\
  12341. Xsystem %s <password> %s #%s\n\n\
  12342. Xwhere 'password' is the list's password, as given to you by the manager of\n\
  12343. Xthis system.\n",
  12344. X         sender, sys.lists[listid].alias, sys.server.address,
  12345. X         sys.lists[listid].alias, sender, request);
  12346. X    COMPLETE_TELNET (f);
  12347. X    fclose (f);
  12348. X    DELIVER_MAIL (sys.lists[listid].owner, FALSE);
  12349. X    return;
  12350. X  }
  12351. X#ifdef bsd
  12352. X  sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12353. X#elif defined (svr4) || defined (svr3)
  12354. X  sighold (SIGINT);
  12355. X  sighold (SIGTERM);
  12356. X#endif
  12357. X#ifdef GO_INTERACTIVE
  12358. X  IN_CRITICAL_SECTION ("subscribe", SEM_LISTFILES);
  12359. X#endif
  12360. X  OPEN_FILE (f, subscribersf, "a", "subscribe"); /* Automatic subscription */
  12361. X  fprintf (f, "%s ", sender);
  12362. X  for (i = 1; i < MAX_SET_OPTIONS; i++)  /* Copy all options */
  12363. X    if (sys.lists[listid].defaults.set_values[i][0] != EOS) {
  12364. X      if (i == 2)
  12365. X    strcpy (password, sys.lists[listid].defaults.set_values[i]);
  12366. X      fprintf (f, "%s ", sys.lists[listid].defaults.set_values[i]);
  12367. X    }
  12368. X    else if (i != 2)    /* Not a password */
  12369. X      fprintf (f, "%s ", default_values[i]);
  12370. X    else
  12371. X      sprintf (password, "%ld", time (0)),
  12372. X      fprintf (f, "%s ", password);
  12373. X  clean_request (params); /* Remove leading blanks from name */
  12374. X  fprintf (f, "%s\n", params);
  12375. X  fclose (f);
  12376. X  REARRANGE_SUBSCRIBERS;
  12377. X#ifdef bsd
  12378. X  sigsetmask (sig_mask);
  12379. X#elif defined (svr4) || defined (svr3)
  12380. X  sigrelse (SIGINT);
  12381. X  sigrelse (SIGTERM);
  12382. X#endif
  12383. X#ifdef GO_INTERACTIVE
  12384. X  OUT_OF_CRITICAL_SECTION ("subscribe", SEM_LISTFILES);
  12385. X#endif
  12386. X  live = (_strstr (sys.serverd_cmdoptions, "-i") != NULL);
  12387. X  _interactive = interactive;
  12388. X  interactive = FALSE;    /* Force email to sender */
  12389. X  chaddr = (sys.lists[listid].defaults.set_values[0][0] == EOS &&
  12390. X        !strcmp (default_values [0], "VARIABLE")) ||
  12391. X          (!strcmp (sys.lists[listid].defaults.set_values[0], "VARIABLE"));
  12392. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  12393. X         COPY_OWNER (ccsub), OK, FALSE, FALSE);
  12394. X  fprintf (f, "You have been added to list %s.\n\
  12395. XThe system has recorded your address as\n\n\t\t\t%s\n\n\
  12396. Xand in order for your messages to get posted (if the list accepts postings),\n\
  12397. Xyou will have to send them from this address, unless the list does not \
  12398. Xrequire\nsubscription for posting.\n\
  12399. XIf a message is ever rejected, please contact the list's owner: %s\n\n",
  12400. X       sys.lists[listid].address, sender, sys.lists[listid].owner);
  12401. X  if (live || chaddr)  {
  12402. X    fprintf (f, "Your initial password is %s. Please change it as soon as you \
  12403. Xcan\nby issuing the following request to %s:\n\n\
  12404. X\t\tSET %s PASSWORD %s new-password\n\nWARNING: Do not use your login password; \
  12405. Xyou will be breaching security at your\nsite.\n\n",
  12406. X         password, sys.server.address, sys.lists[listid].alias, password);
  12407. X    if (live)
  12408. X      fprintf (f, "This system may accept Internet TCP/IP connections for \
  12409. Xprocessing of live\nrequests, and the password will be used to give you \
  12410. Xsubscriber privileges.\nFor more information, send a 'help live' request to \
  12411. X%s.\n\n", sys.server.address);
  12412. X    if (chaddr)
  12413. X      fprintf (f, "You may change the address you \
  12414. Xare subscribed with (currently %s)\nwith the following request:\n\n\
  12415. X\t\tSET %s ADDRESS %s new-address\n\nassuming that you keep the same \
  12416. Xpassword.\n\n", sender, sys.lists[listid].alias, password);
  12417. X  }
  12418. X  fprintf (f, "For information on this service and how to use it, send the \
  12419. Xfollowing\nrequest in the body of a mail message to %s:\n\n\t\t\tHELP\n\n\
  12420. XAll requests should be addressed to %s.\n", sys.server.address,
  12421. X       sys.server.address);
  12422. X  fclose (f);
  12423. X  strcpy (shell, "cat");
  12424. X#ifdef GO_INTERACTIVE
  12425. X  IN_CRITICAL_SECTION ("subscribe", SEM_LISTFILES);
  12426. X#endif
  12427. X  if ((f = fopen (welcomef, "r"))) {
  12428. X    fgets (shell, 3, f);
  12429. X    if (!strncmp (shell, "#!", 2)) {
  12430. X      fgets (shell, MAX_LINE - 2, f);
  12431. X      if (shell [strlen (shell) - 1] == '\n')
  12432. X    shell [strlen (shell) - 1] = EOS;
  12433. X    }
  12434. X    else
  12435. X      strcpy (shell, "cat");
  12436. X    fclose (f);
  12437. X  }
  12438. X  syscom ("%s %s >> %s", shell, welcomef, mailforwardf);
  12439. X#ifdef GO_INTERACTIVE
  12440. X  OUT_OF_CRITICAL_SECTION ("subscribe", SEM_LISTFILES);
  12441. X#endif
  12442. X  APPEND_TELNET ("subscribe");
  12443. X  DELIVER_MAIL (sender, COPY_OWNER (ccsub));
  12444. X  interactive = _interactive;
  12445. X  if (interactive) { /* Notify ilp client */
  12446. X    create_header (&f, mailforwardf, sys.server.address, sender, request,
  12447. X           COPY_OWNER (ccsub), OK, FALSE, FALSE);
  12448. X    fprintf (f, "User %s was successfully subscribed to list %s.\n", sender,
  12449. X         sys.lists[listid].address);
  12450. X    fclose (f);
  12451. X  }
  12452. X}
  12453. X
  12454. X/*
  12455. X  Tell 'sender' what list(s) he/she is subscribed in.
  12456. X*/
  12457. X
  12458. Xvoid which (char *request, char *params, char *sender)
  12459. X{
  12460. X  char subscribersf [MAX_LINE];
  12461. X  char aliasesf [MAX_LINE];
  12462. X  char param [MAX_LINE];
  12463. X  FILE *f;
  12464. X  int i;
  12465. X
  12466. X  sprintf (request + strlen (request), "%s", params); /* Used as a subject */
  12467. X  RESET (param);
  12468. X  sscanf (params, "%s", param);
  12469. X  if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
  12470. X    reject_mail (sender, request, tsprintf ("Invalid WHICH option%s\n\
  12471. XSyntax: which\n", params), SYNTAX_ERROR, 0);
  12472. X    return;
  12473. X  }
  12474. X  create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  12475. X         OK, FALSE, FALSE);
  12476. X  fprintf (f, "%s: You are subscribed to the following lists;\nif none appear, \
  12477. Xyou are not subscribed to any:\n", sender);
  12478. X  for (i = 0; i < nlists; ++i) {
  12479. X    setup_string (subscribersf, sys.lists[i].alias, SUBSCRIBERS);
  12480. X    setup_string (aliasesf, sys.lists[i].alias, ALIASES);
  12481. X    if (subscribed (report, sender, subscribersf, NULL, NULL, aliasesf, TRUE) ==
  12482. X    SUBSCRIBED)
  12483. X      fprintf (f, "%s\n", sys.lists[i].alias);
  12484. X  }
  12485. X  COMPLETE_TELNET (f);
  12486. X  fclose (f);
  12487. X  DELIVER_MAIL (sender, FALSE);
  12488. X}
  12489. X
  12490. X/*
  12491. X  Set options for user if he/she is subscribed. If the list is remote,
  12492. X  the request is forwarded. If resetting MAIL ACK/NOACK/POSTPONE from
  12493. X  DIGEST, send a partial digest.
  12494. X  Adding more SET options:
  12495. X  - In defs.h, define the new MAX_SET_OPTIONS.
  12496. X  - In global.h, define the new option in options[], the valid
  12497. X    values in values[] and the default_values[].
  12498. X  - the MAIL option should be second in the list; this assumption is made by
  12499. X    list and listproc.
  12500. X*/
  12501. X
  12502. Xvoid set (char *request, char *params, char *sender)
  12503. X{
  12504. X  FILE *f, *from, *to;
  12505. X  char error [10240];
  12506. X  char option [MAX_LINE];
  12507. X  char subscriber [MAX_LINE];
  12508. X  char oldmodes [MAX_SET_OPTIONS] [MAX_LINE];
  12509. X  char newmode [MAX_LINE];
  12510. X  char moreparams [MAX_LINE];
  12511. X  char name [MAX_LINE];
  12512. X  char address [MAX_LINE];
  12513. X  char *blank;
  12514. X  int  i, j, index;
  12515. X  long int sig_mask;
  12516. X  BOOLEAN status, ok_to_reset_address = FALSE;
  12517. X
  12518. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  12519. X           params); /* Used as a subject */
  12520. X  error[0] = option[0] = moreparams[0] = RESET (newmode);
  12521. X  sscanf (params, "%s %s %s\n", option, newmode, moreparams); /* Get params */
  12522. X  upcase (option);
  12523. X  upcase (newmode);
  12524. X  if (matched_rlists) { /* Request for a remote list; notify sender */
  12525. X    NOTIFY_OF_REQUEST_FORWARDING;
  12526. X    FORWARD_REQUEST;
  12527. X    return;
  12528. X  }
  12529. X  if ((sys.lists[listid].defaults.set_values[0][0] == EOS &&
  12530. X       !strcmp (default_values [0], "VARIABLE")) ||
  12531. X      (!strcmp (sys.lists[listid].defaults.set_values[0], "VARIABLE")))
  12532. X    ok_to_reset_address = TRUE;
  12533. X  if (!(status = subscribed (report, sender, subscribersf, newsf, peersf,
  12534. X                 aliasesf, TRUE))) {
  12535. X    sprintf (error, "%s: You are not subscribed to %s\n", sender,
  12536. X             sys.lists[listid].address);
  12537. X    if (alternate_addresses) {
  12538. X      sprintf (error + strlen (error),
  12539. X           "\nIn addition, the system found the following \
  12540. Xaddress(es) that resemble yours.\nIf one of these is you, please resend your \
  12541. Xmessage from that one%s:\n\n",
  12542. X           (ok_to_reset_address ?
  12543. X        ", or use the\n'set <list> address' request to change the \
  12544. Xaddress you are subscribed with" :
  12545. X        ""));
  12546. X      for (i = 0; alternate_addresses[i]; ++i)
  12547. X    sprintf (error + strlen (error), "%s\n", alternate_addresses[i]),
  12548. X    free ((char *) alternate_addresses[i]);
  12549. X      free ((char **) alternate_addresses);
  12550. X      alternate_addresses = NULL;
  12551. X      strcat (error, "\n");
  12552. X    }
  12553. X    reject_mail (sender, request, error, INVALID_REQ, 0);
  12554. X    return;
  12555. X  }
  12556. X  else if (status > SUBSCRIBED) { /* Notify manager */
  12557. X    NOTIFY_MANAGER ("Attempt to set mode for news or peer");
  12558. X    return;
  12559. X  }
  12560. X  if (option[0] != EOS) {
  12561. X    for (index = 0; index < MAX_SET_OPTIONS; index++)
  12562. X      if (! strcmp (option, options[index]))
  12563. X    break;
  12564. X    if (index == MAX_SET_OPTIONS) {
  12565. X      reject_mail (sender, request, tsprintf ("Invalid SET option %s\n\n\
  12566. XSyntax: set <list> [<option> <arg[s]>]\n\
  12567. X\toption: mail, password, address, conceal\n\
  12568. X\targ for 'mail': ack/noack/postpone/digest\n\
  12569. X\targs for 'password': <current-password> <new-password>\n\
  12570. X\targs for 'address': <current-password> <new-address>\n\
  12571. X\targ for 'conceal': yes/no\n", option), SYNTAX_ERROR, 0);
  12572. X      return;
  12573. X    }
  12574. X    if (newmode[0] == EOS ||
  12575. X    (!strcmp (option, options[0]) && moreparams[0] == EOS) ||
  12576. X    (!strcmp (option, options[2]) && moreparams[0] == EOS)) {
  12577. X      reject_mail (sender, request, tsprintf ("Missing SET %s value\n\n\
  12578. XSyntax: set <list> [<option> <arg[s]>]\n\
  12579. X\toption: mail, password, address, conceal\n\
  12580. X\targ for 'mail': ack/noack/postpone/digest\n\
  12581. X\targs for 'password': <current-password> <new-password>\n\
  12582. X\targs for 'address': <current-password> <new-address>\n\
  12583. X\targ for 'conceal': yes/no\n", options[index]), SYNTAX_ERROR, 0);
  12584. X      return;
  12585. X    }
  12586. X    if (index > 0 &&
  12587. X    !strinstr (values[index], (index == 1 || index == 3 ?
  12588. X                   newmode : moreparams))) {
  12589. X      reject_mail (sender, request, tsprintf ("Invalid SET %s value %s\n\n\
  12590. XSyntax: set <list> [<option> <arg[s]>]\n\
  12591. X\toption: mail, password, address, conceal\n\
  12592. X\targ for 'mail': ack/noack/postpone/digest\n\
  12593. X\targs for 'password': <current-password> <new-password>\n\
  12594. X\targs for 'address': <current-password> <new-address>\n\
  12595. X\targ for 'conceal': yes/no\n", options[index], newmode), SYNTAX_ERROR, 0);
  12596. X      return;
  12597. X    }
  12598. X  }
  12599. X  if (moreparams[0] != EOS && strcmp (option, options[0]) &&
  12600. X      strcmp (option, options[2]) && !(sys.options & RELAXED_SYNTAX)) {
  12601. X    reject_mail (sender, request, tsprintf ("Too many SET parameters: %s\n\n\
  12602. XSyntax: set <list> [<option> <arg[s]>]\n\
  12603. X\toption: mail, password, address, conceal\n\
  12604. X\targ for 'mail': ack/noack/postpone/digest\n\
  12605. X\targs for 'password': <current-password> <new-password>\n\
  12606. X\targs for 'address': <current-password> <new-address>\n\
  12607. X\targ for 'conceal': yes/no\n", moreparams), SYNTAX_ERROR, 0);
  12608. X    return;
  12609. X  }
  12610. X  if (option[0] == EOS) { /* Status inquiry */
  12611. X    if (! one_rejection) {
  12612. X#ifdef GO_INTERACTIVE
  12613. X      IN_CRITICAL_SECTION ("set", SEM_LISTFILES);
  12614. X#endif
  12615. X#if defined (__NeXT__) || defined (__convex__) || defined (unknown_port)
  12616. X      syscom ("grep -i '^[ \t]*%s ' %s | \
  12617. X%s '{ printf \"%%s\", $1; for (i = 2; i <= %d; ++i) printf \" %%s\", $i; \
  12618. Xprintf \"\\n\" }' > %s",
  12619. X        sender, subscribersf, AWK, MAX_SET_OPTIONS, OLD_SUBSCRIBERS);
  12620. X#else
  12621. X      syscom ("grep -i '^[ \t]*%s ' %s | %s -d' ' -f1-%d > %s", sender,
  12622. X        subscribersf, CUT, MAX_SET_OPTIONS, OLD_SUBSCRIBERS);
  12623. X#endif
  12624. X      create_header (&f, mailforwardf, sys.server.address, sender, request,
  12625. X             COPY_OWNER (ccset), OK, FALSE, FALSE);
  12626. X      fprintf (f, "Current settings are:\n\n");
  12627. X      OPEN_FILE (from, OLD_SUBSCRIBERS, "r", "set");
  12628. X      for (i = 0; i < MAX_SET_OPTIONS; i++)
  12629. X    RESET (newmode),
  12630. X    fscanf (from, "%s ", newmode),
  12631. X    fprintf (f, "%s = %s\n", options[i], newmode);
  12632. X      fflush (f);
  12633. X      fclose (from);
  12634. X      COMPLETE_TELNET (f);
  12635. X      fclose (f);
  12636. X#ifdef GO_INTERACTIVE
  12637. X      OUT_OF_CRITICAL_SECTION ("set", SEM_LISTFILES);
  12638. X#endif
  12639. X      DELIVER_MAIL (sender, COPY_OWNER (ccset));
  12640. X      unlink (OLD_SUBSCRIBERS);
  12641. X    }
  12642. X    return;
  12643. X  }
  12644. X  /* Change of mode */
  12645. X#ifdef GO_INTERACTIVE
  12646. X  IN_CRITICAL_SECTION ("set", SEM_LISTFILES);
  12647. X#endif
  12648. X  if (cp (subscribersf, OLD_SUBSCRIBERS))
  12649. X    gexit (16);
  12650. X  OPEN_FILE (from, OLD_SUBSCRIBERS, "r", "set");
  12651. X  OPEN_FILE (to, NEW_SUBSCRIBERS, "w", "set");
  12652. X  while (!feof (from)) {
  12653. X    subscriber[0] = RESET (name);
  12654. X    if (!extract_subscriber (from, subscriber, FALSE)) {
  12655. X      NOTIFY_MANAGER_OF_INVALID_USER_ADDRESS (subscriber);
  12656. X      create_header (&f, mailforwardf, sys.server.address, sender, request,
  12657. X             COPY_OWNER (ccset), OK, FALSE, FALSE);
  12658. X      fprintf (f, "Sorry, a system error has occured. Try again later.\n");
  12659. X      COMPLETE_TELNET (f);
  12660. X      fclose (f);
  12661. X      fclose (from);
  12662. X      fclose (to);
  12663. X      unlink (OLD_SUBSCRIBERS);
  12664. X      unlink (NEW_SUBSCRIBERS);
  12665. X#ifdef GO_INTERACTIVE
  12666. X      OUT_OF_CRITICAL_SECTION ("set", SEM_LISTFILES);
  12667. X#endif
  12668. X      DELIVER_MAIL (sender, COPY_OWNER (ccset));
  12669. X      return;
  12670. X    }
  12671. X    strcpy (oldmodes[0], subscriber);
  12672. X    for (i = 1; i < MAX_SET_OPTIONS; i++)
  12673. X      RESET (oldmodes[i]),
  12674. X      fscanf (from, "%s ", oldmodes[i]);
  12675. X    fgets (name, MAX_LINE - 2, from);
  12676. X    upcase (subscriber);
  12677. X    if (!feof (from)) {
  12678. X      if (! strcmp (sender, subscriber))
  12679. X    for (i = 0; i < MAX_SET_OPTIONS; i++) {
  12680. X      if (i == 0) {
  12681. X        if (!strcmp (option, options[0]))
  12682. X          if (!ok_to_reset_address)
  12683. X        fprintf (to, "%s ", subscriber),
  12684. X        reject_mail (sender, request, "Changing of address is not \
  12685. Xallowed for this list.\n", RESTRICTED_REQ, 0);
  12686. X          else
  12687. X        if (strcmp (newmode, oldmodes[2])) /* Invalid password */
  12688. X          fprintf (to, "%s ", subscriber),
  12689. X          reject_mail (sender, request,
  12690. X                   tsprintf ("Password verification failure: %s\n",
  12691. X                     newmode), SYNTAX_ERROR, 0);
  12692. X        else {
  12693. X          sprintf (address, "From %s", moreparams);
  12694. X          if (!extract_sender (address))
  12695. X            fprintf (to, "%s ", subscriber),
  12696. X            reject_mail (sender, request,
  12697. X                 tsprintf ("Invalid address: %s\n", moreparams),
  12698. X                 SYNTAX_ERROR, 0);
  12699. X          else {
  12700. X            sprintf (address, "^[\t ]*%s ", sender);
  12701. X            if (cp (aliasesf, OLD_ALIASES))
  12702. X              gexit (16);
  12703. X            REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
  12704. X#ifdef bsd
  12705. X            sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12706. X#elif defined (svr4) || defined (svr3)
  12707. X            sighold (SIGINT);
  12708. X            sighold (SIGTERM);
  12709. X#endif
  12710. X            if (mv (NEW_ALIASES, aliasesf))
  12711. X              gexit (16);
  12712. X#ifdef bsd
  12713. X            sigsetmask (sig_mask);
  12714. X#elif defined (svr4) || defined (svr3)
  12715. X            sigrelse (SIGINT);
  12716. X            sigrelse (SIGTERM);
  12717. X#endif
  12718. X            if (cp (ALIASESF, OLD_ALIASES))
  12719. X              gexit (16);
  12720. X            REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
  12721. X#ifdef bsd
  12722. X            sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12723. X#elif defined (svr4) || defined (svr3)
  12724. X            sighold (SIGINT);
  12725. X            sighold (SIGTERM);
  12726. X#endif
  12727. X            if (mv (NEW_ALIASES, ALIASESF))
  12728. X              gexit (16);
  12729. X#ifdef bsd
  12730. X    sigsetmask (sig_mask);
  12731. X#elif defined (svr4) || defined (svr3)
  12732. X    sigrelse (SIGINT);
  12733. X    sigrelse (SIGTERM);
  12734. X#endif
  12735. X            sprintf (address, " %s[\t ]*$", sender);
  12736. X            if (cp (aliasesf, OLD_ALIASES))
  12737. X              gexit (16);
  12738. X            REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
  12739. X#ifdef bsd
  12740. X            sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12741. X#elif defined (svr4) || defined (svr3)
  12742. X            sighold (SIGINT);
  12743. X            sighold (SIGTERM);
  12744. X#endif
  12745. X            if (mv (NEW_ALIASES, aliasesf))
  12746. X              gexit (16);
  12747. X#ifdef bsd
  12748. X            sigsetmask (sig_mask);
  12749. X#elif defined (svr4) || defined (svr3)
  12750. X            sigrelse (SIGINT);
  12751. X            sigrelse (SIGTERM);
  12752. X#endif
  12753. X            if (cp (ALIASESF, OLD_ALIASES))
  12754. X              gexit (16);
  12755. X            REMOVE_ADDRESS (address, OLD_ALIASES, NEW_ALIASES);
  12756. X#ifdef bsd
  12757. X            sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12758. X#elif defined (svr4) || defined (svr3)
  12759. X            sighold (SIGINT);
  12760. X            sighold (SIGTERM);
  12761. X#endif
  12762. X            if (mv (NEW_ALIASES, ALIASESF))
  12763. X              gexit (16);
  12764. X#ifdef bsd
  12765. X            sigsetmask (sig_mask);
  12766. X#elif defined (svr4) || defined (svr3)
  12767. X            sigrelse (SIGINT);
  12768. X            sigrelse (SIGTERM);
  12769. X#endif
  12770. X            unlink (OLD_ALIASES);
  12771. X            if (echo_append (tsprintf ("%s %s", subscriber,
  12772. X                           moreparams), aliasesf))
  12773. X              gexit (16);
  12774. X            if (echo_append (tsprintf ("%s %s", subscriber,
  12775. X                           moreparams), ALIASESF))
  12776. X              gexit (16);
  12777. X            fprintf (to, "%s ", moreparams); /* Put new address */
  12778. X          }
  12779. X        }
  12780. X        else
  12781. X          fprintf (to, "%s ", subscriber);
  12782. X      }
  12783. X      else if (i == 2 && !strcmp (option, options[2]) &&
  12784. X           strcmp (newmode, oldmodes[i])) /* Invalid old password */
  12785. X        fprintf (to, "%s ", oldmodes[i]),
  12786. X        reject_mail (sender, request,
  12787. X             tsprintf ("Password verification failure: %s\n", newmode),
  12788. X             SYNTAX_ERROR, 0);
  12789. X      else
  12790. X        fprintf (to, "%s ", (i == index ? 
  12791. X             (strcmp (option, options[2]) ? newmode : moreparams) :
  12792. X             oldmodes[i]));
  12793. X      if (strcmp (newmode, DIGEST) && strcmp (newmode, POSTPONE) &&
  12794. X          !strcmp (oldmodes[i], DIGEST))
  12795. X        /* Turned off DIGEST, send a partial digest */
  12796. X        syscom ("%s %s -i%s %s", LIST, sys.lists[listid].alias,
  12797. X           sender, sys.lists[i].cmdoptions);
  12798. X    }
  12799. X      else
  12800. X    for (i = 0; i < MAX_SET_OPTIONS; i++)
  12801. X      fprintf (to, "%s ", oldmodes[i]);
  12802. X      clean_request (name); /* Remove leading blanks */
  12803. X      fprintf (to, "%s", name);
  12804. X    }
  12805. X  }
  12806. X  fclose (from);
  12807. X  fclose (to);
  12808. X#ifdef bsd
  12809. X    sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  12810. X#elif defined (svr4) || defined (svr3)
  12811. X    sighold (SIGINT);
  12812. X    sighold (SIGTERM);
  12813. X#endif
  12814. X  if (mv (NEW_SUBSCRIBERS, subscribersf))
  12815. X    gexit (16);
  12816. X#ifdef bsd
  12817. X    sigsetmask (sig_mask);
  12818. X#elif defined (svr4) || defined (svr3)
  12819. X    sigrelse (SIGINT);
  12820. X    sigrelse (SIGTERM);
  12821. X#endif
  12822. X  unlink (OLD_SUBSCRIBERS);
  12823. X#ifdef GO_INTERACTIVE
  12824. X  OUT_OF_CRITICAL_SECTION ("set", SEM_LISTFILES);
  12825. X#endif
  12826. X  if (! one_rejection) {
  12827. X    blank = request;
  12828. X    (index == 0 ? (j = 3) : (j = 4));
  12829. X    for (i = 0; i < j; i++)
  12830. X      blank = strchr (blank + 1, ' ');
  12831. X    ++blank;
  12832. X    shadow_password (blank);
  12833. X    create_header (&f, mailforwardf, sys.server.address, 
  12834. X           (index == 0 ? moreparams : sender), request,
  12835. X           COPY_OWNER (ccset), OK, FALSE, FALSE);
  12836. X    fprintf (f, "%s mode reset to %s\n", options[index],
  12837. X         (index == 0 || index == 2 ? moreparams : newmode));
  12838. X    COMPLETE_TELNET (f);
  12839. X    fclose (f);
  12840. X    if (!index) {
  12841. X      DELIVER_MAIL (moreparams, COPY_OWNER (ccset));
  12842. X    }
  12843. X    else
  12844. X      DELIVER_MAIL (sender, COPY_OWNER (ccset));
  12845. X  }
  12846. X}
  12847. X
  12848. X/*
  12849. X  Provide user with the current list of subscribers. Peer servers are
  12850. X  also notified and they send their own compilations. If the list is
  12851. X  remote, the request is forwarded.
  12852. X  For private lists, only members may make this request.
  12853. X*/
  12854. X
  12855. Xvoid recipients (char *request, char *params, char *sender)
  12856. X{
  12857. X  char param [MAX_LINE];
  12858. X  FILE *f;
  12859. X
  12860. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  12861. X           params); /* Used as a subject */
  12862. X  if (matched_rlists) { /* Request for a remote list; notify sender */
  12863. X    NOTIFY_OF_REQUEST_FORWARDING;
  12864. X    FORWARD_REQUEST;
  12865. X    return;
  12866. X  }
  12867. X  RESET (param);
  12868. X  sscanf (params, "%s", param);
  12869. X  if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
  12870. X    reject_mail (sender, request, tsprintf ("Invalid RECIPIENTS option%s\n\
  12871. XSyntax: recipients <list> (or review <list>)\n", params), SYNTAX_ERROR, 0);
  12872. X    return;
  12873. X  }
  12874. X  if (sys.lists[listid].options & NON_AUTO_SUB) { /* Private list */
  12875. X    if (subscribed (report, sender, subscribersf, NULL, NULL, aliasesf, TRUE) ==
  12876. X    NOTSUBSCRIBED) {
  12877. X      MEMBERS_ONLY;
  12878. X      return;
  12879. X    }
  12880. X  }
  12881. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  12882. X         COPY_OWNER (ccrec), OK, FALSE, FALSE);
  12883. X  fprintf (f, "Here is the current list of non-concealed subscribers:\n\n");
  12884. X  fclose (f);
  12885. X#ifdef GO_INTERACTIVE
  12886. X  IN_CRITICAL_SECTION ("recipients", SEM_LISTFILES);
  12887. X#endif
  12888. X#if defined (__NeXT__) || defined (__convex__) || defined (unknown_port)
  12889. X  syscom ("%s '{ printf \"%%s\", $1; for (i = %d; i <= %d; ++i) \
  12890. Xprintf \" %%s\", $i; printf \"\\n\" }' %s | grep -i ' NO ' | \
  12891. X%s '{ printf \"%%s\", $1; for (i = 3; i <= %d; ++i) printf \" %%s\", $i; \
  12892. Xprintf \"\\n\" }' > %s",
  12893. X      AWK, MAX_SET_OPTIONS, MAX_SET_OPTIONS + 5, subscribersf, AWK,
  12894. X      MAX_SET_OPTIONS + 4, recipf);
  12895. X#else
  12896. X  syscom ("%s -d\" \" -f1,%d-%d %s | grep -i ' NO ' | %s -d\" \" -f1,3-%d \
  12897. X> %s", CUT, MAX_SET_OPTIONS, MAX_SET_OPTIONS + 5, subscribersf, CUT,
  12898. X      MAX_SET_OPTIONS + 4, recipf);
  12899. X#endif
  12900. X  syscom ("%s -f %s %s >> %s", AWK, AWK_PROG, recipf, mailforwardf);
  12901. X  syscom ("echo Total number of subscribers: `cat %s | wc -l` \
  12902. X\"(`cat %s | wc -l | tr -d ' '` shown here)\" >> %s", subscribersf, recipf,
  12903. X      mailforwardf);
  12904. X#ifdef GO_INTERACTIVE
  12905. X  OUT_OF_CRITICAL_SECTION ("recipients", SEM_LISTFILES);
  12906. X#endif
  12907. X  unlink (recipf);
  12908. X  APPEND_TELNET ("recipients");
  12909. X  DELIVER_MAIL (sender, COPY_OWNER (ccrec));
  12910. X  notify_peer_servers (peersf, "review", params, sender);
  12911. X}
  12912. X
  12913. X/*
  12914. X  Provide user with general information about the list. A reminder, the
  12915. X  actual text is in the INFO_FILE. If the list is remote, the request
  12916. X  is forwarded.
  12917. X*/
  12918. X
  12919. Xvoid info (char *request, char *params, char *sender)
  12920. X{
  12921. X  char param [MAX_LINE];
  12922. X  char shell [MAX_LINE];
  12923. X  FILE *f;
  12924. X
  12925. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  12926. X           params); /* Used as a subject */
  12927. X  if (matched_rlists) { /* Request for a remote list; notify sender */
  12928. X    NOTIFY_OF_REQUEST_FORWARDING;
  12929. X    FORWARD_REQUEST;
  12930. X    return;
  12931. X  }
  12932. X  RESET (param);
  12933. X  sscanf (params, "%s", param);
  12934. X  if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
  12935. X    reject_mail (sender, request, tsprintf ("Invalid INFORMATION option%s\n\
  12936. XSyntax: information <list>\n", params), SYNTAX_ERROR, 0);
  12937. X    return;
  12938. X  }
  12939. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  12940. X         COPY_OWNER (ccinfo), OK, FALSE, FALSE);
  12941. X  fclose (f);
  12942. X#ifdef GO_INTERACTIVE
  12943. X  IN_CRITICAL_SECTION ("info", SEM_LISTFILES);
  12944. X#endif
  12945. X  strcpy (shell, "cat");
  12946. X  if ((f = fopen (infof, "r"))) {
  12947. X    fgets (shell, 3, f);
  12948. X    if (!strncmp (shell, "#!", 2)) {
  12949. X      fgets (shell, MAX_LINE - 2, f);
  12950. X      if (shell [strlen (shell) - 1] == '\n')
  12951. X    shell [strlen (shell) - 1] = EOS;
  12952. X    }
  12953. X    else
  12954. X      strcpy (shell, "cat");
  12955. X    fclose (f);
  12956. X  }
  12957. X  syscom ("%s %s >> %s", shell, infof, mailforwardf);
  12958. X#ifdef GO_INTERACTIVE
  12959. X  OUT_OF_CRITICAL_SECTION ("info", SEM_LISTFILES);
  12960. X#endif
  12961. X  APPEND_TELNET ("info");
  12962. X  DELIVER_MAIL (sender, COPY_OWNER (ccinfo));
  12963. X}
  12964. X
  12965. X/*
  12966. X  Collect and send statistics about all subscribers, by grepping through
  12967. X  HEADERS. If a user has selected particular names (asterisks are OK) then
  12968. X  give statistics about these people only. Also include a total count
  12969. X  of messages on file. Peer servers are also notified and they send their
  12970. X  own compilations. If the list is remote, the request is forwarded.
  12971. X  For private lists, only members may make this request.
  12972. X*/
  12973. X
  12974. Xvoid stats (char *request, char *params, char *sender)
  12975. X{
  12976. X  FILE *f;
  12977. X  char junk [MAX_LINE];
  12978. X  struct stat stat_buf;
  12979. X
  12980. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  12981. X           params); /* Used as a subject */
  12982. X  if (matched_rlists) { /* Request for a remote list; notify sender */
  12983. X    NOTIFY_OF_REQUEST_FORWARDING;
  12984. X    FORWARD_REQUEST;
  12985. X    return;
  12986. X  }
  12987. X  if (sys.lists[listid].options & NON_AUTO_SUB) { /* Private list */
  12988. X    if (subscribed (report, sender, subscribersf, NULL, NULL, aliasesf, TRUE) ==
  12989. X    NOTSUBSCRIBED) {
  12990. X      MEMBERS_ONLY;
  12991. X      return;
  12992. X    }
  12993. X  }
  12994. X  params [strlen (params) - 1] = EOS; /* Remove \n */
  12995. X  RESET (junk);
  12996. X  sscanf (params, "%s", junk);
  12997. X  if (junk[0] == EOS) /* No specific subscribers to report on */
  12998. X    RESET (params);
  12999. X  if (stat (headersf, &stat_buf)) {
  13000. X    NOTIFY_OF_BAD_ARCHIVE ("Sorry, no mail archive found.\n", NULL, OK);
  13001. X    return;
  13002. X  }
  13003. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  13004. X         COPY_OWNER (ccstat), OK, FALSE, FALSE);
  13005. X  fprintf (f, "Here are the number of messages per non-concealed subscriber:\
  13006. X\n\n");
  13007. X  fclose (f);
  13008. X#ifdef GO_INTERACTIVE
  13009. X  IN_CRITICAL_SECTION ("stats", SEM_LISTFILES);
  13010. X#endif
  13011. X  EXEC_STATS;
  13012. X#ifdef GO_INTERACTIVE
  13013. X  OUT_OF_CRITICAL_SECTION ("stats", SEM_LISTFILES);
  13014. X#endif
  13015. X  APPEND_TELNET ("stats");
  13016. X  DELIVER_MAIL (sender, COPY_OWNER (ccstat));
  13017. X  notify_peer_servers (peersf, "stat", params, sender);
  13018. X}
  13019. X
  13020. X/*
  13021. X  Exit with a shutdown status if the correct password is provided.
  13022. X*/
  13023. X
  13024. Xvoid Shutdown (char *request, char *params, char *sender)
  13025. X{
  13026. X  char passwd [MAX_LINE];
  13027. X
  13028. X  sscanf (params, "%s\n", passwd);
  13029. X  if (!strcmp (sys.server.password, passwd))
  13030. X    report_progress (report, "SHUTDOWN request accepted", TRUE),
  13031. X    gexit (6); /* Exit status of 6 signifies a shutdown request */
  13032. X  reject_mail (sender, request, tsprintf ("Unrecognized request %s\n", request),
  13033. X           INVALID_REQ, 0);
  13034. X}
  13035. X
  13036. X/*
  13037. X  Set the global variable 'restart_sys' to TRUE if the correct password
  13038. X  is given.
  13039. X*/
  13040. X
  13041. Xvoid restart (char *request, char *params, char *sender)
  13042. X{
  13043. X  char passwd [MAX_LINE];
  13044. X
  13045. X  sscanf (params, "%s\n", passwd);
  13046. X  if (!strcmp (sys.server.password, passwd)) { 
  13047. X    report_progress (report, "RESTART request accepted\n", FALSE);
  13048. X    restart_sys = TRUE;
  13049. X    return;
  13050. X  }
  13051. X  reject_mail (sender, request, tsprintf ("Unrecognized request %s\n", request),
  13052. X           INVALID_REQ, 0);
  13053. X}
  13054. X
  13055. X/*
  13056. X  Provide 'sender' with a list of all mailing lists served by this server,
  13057. X  as well as any remote lists known to this server.
  13058. X*/
  13059. X
  13060. Xvoid lists (char *request, char *params, char *sender)
  13061. X{
  13062. X  char param [MAX_LINE];
  13063. X  FILE *f;
  13064. X  int i, alslen, lstlen, adrlen, len, _nlists;
  13065. X  REMOTE *r = rlists, *s = rlists;
  13066. X
  13067. X  sprintf (request + strlen (request), "%s", params); /* Used as a subject */
  13068. X  RESET (param);
  13069. X  sscanf (params, "%s", param);
  13070. X  if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
  13071. X    reject_mail (sender, request, tsprintf ("Invalid LISTS option%s\n\
  13072. XSyntax: lists\n", params), SYNTAX_ERROR, 0);
  13073. X    return;
  13074. X  }
  13075. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  13076. X         COPY_OWNER (cclists), OK, FALSE, FALSE);
  13077. X  adrlen = -99;
  13078. X  for (i = 0, _nlists = 0; i < nlists; ++i) /* Get longest address */
  13079. X    if (!(sys.lists[i].options & CONCEAL_LIST)) {
  13080. X      ++_nlists;
  13081. X      if ((len = strlen (sys.lists[i].address)) > adrlen)
  13082. X    adrlen = len;
  13083. X    }
  13084. X  fprintf (f, "Here is the current active list of the %d mailing lists \
  13085. Xserved by this server:\n\n", _nlists);
  13086. X  for (i = 0; i < nlists; ++i)
  13087. X    if (!(sys.lists[i].options & CONCEAL_LIST))
  13088. X      fprintf (f, "%-*s  %s\n", adrlen, sys.lists[i].address,
  13089. X           sys.lists[i].comment);
  13090. X
  13091. X  if (rlists) { /* List all remote lists */
  13092. X    i = 0;
  13093. X    fprintf (f, "\nIn addition, the following remote lists are known to this \
  13094. Xserver:\n\n");
  13095. X    alslen = strlen ("ALIAS");
  13096. X    adrlen = strlen ("FULL ADDRESS");
  13097. X    lstlen = strlen ("LISTPROCESSOR ADDRESS");
  13098. X    while (s) {
  13099. X      if ((len = strlen (s->alias)) > alslen)
  13100. X    alslen = len;
  13101. X      if ((len = strlen (s->address)) > adrlen)
  13102. X        adrlen = len;
  13103. X      if ((len = strlen (s->listproc)) > lstlen)
  13104. X        lstlen = len;
  13105. X      s = s->next;
  13106. X    }
  13107. X    fprintf (f, "%-*s %-*s %-*s COMMENT\n%-*s %-*s %-*s -------\n",
  13108. X       alslen, "ALIAS", adrlen, "FULL ADDRESS", lstlen, "LISTPROCESSOR ADDRESS",
  13109. X       alslen, "-----", adrlen, "------------", lstlen, "---------------------");
  13110. X    while (r)
  13111. X      ++i,
  13112. X      fprintf (f, "%-*s %-*s %-*s %s\n", alslen, r->alias, adrlen,
  13113. X           r->address, lstlen, r->listproc, r->comment),
  13114. X      r = r->next;
  13115. X    fprintf (f, "\nTotal number of remote lists: %d. Requests sent to \
  13116. Xthis server for these\nremote lists will be forwarded to the servers \
  13117. Xserving these lists.\n", i);
  13118. X  }
  13119. X  COMPLETE_TELNET (f);
  13120. X  fclose (f);
  13121. X  DELIVER_MAIL (sender, COPY_OWNER (cclists));
  13122. X}
  13123. X
  13124. X/*
  13125. X  Get an index of files for the specified archive, or the master archive
  13126. X  if none specified. Private archives require a password to list their
  13127. X  files.
  13128. X
  13129. X  Adapted USER CONTRIBUTED FUNCTION: Stefan Schroer.
  13130. X*/
  13131. X
  13132. Xvoid Index (char *request, char *params, char *sender)
  13133. X{
  13134. X  FILE *f, *index, *dir, *master;
  13135. X  char archive [MAX_LINE];
  13136. X  char arch [MAX_LINE];
  13137. X  char cur_archive [MAX_LINE];
  13138. X  char line [MAX_LINE];
  13139. X  char file [MAX_LINE];
  13140. X  char fullpath [MAX_LINE];
  13141. X  char moreparams [MAX_LINE];
  13142. X  char fullname [MAX_LINE];
  13143. X  char desc [MAX_LINE];
  13144. X  char junk [MAX_LINE];
  13145. X  char user_password [MAX_LINE];
  13146. X  char sys_password [MAX_LINE];
  13147. X  char *slash;
  13148. X  BOOLEAN found, continued, header_printed, all = FALSE;
  13149. X  int count, parts, i;
  13150. X  long int *filesizes;
  13151. X
  13152. X  sprintf (request + strlen (request), "%s", params); /* Used as a subject */
  13153. X  archive[0] = fullpath[0] = fullname[0] = 
  13154. X  cur_archive[0] = RESET (moreparams);
  13155. X  sscanf (params, "%s %s %s", archive, user_password, moreparams);
  13156. X  if (archive[0] == '/') /* No archive given, just password */
  13157. X    strcpy (user_password, archive),
  13158. X    RESET (archive);
  13159. X  else if (!strcmp (archive, "-ALL"))
  13160. X    all = TRUE,
  13161. X    RESET (archive);
  13162. X  if (user_password[0] == '/') /* Remove leading '/' */
  13163. X    sprintf (user_password, "%s", user_password + 1);
  13164. X  else if (!strcmp (user_password, "-ALL"))
  13165. X    RESET (user_password),
  13166. X    all = TRUE;
  13167. X  locase (archive);
  13168. X  if (moreparams[0] != EOS)
  13169. X    if (strcmp (moreparams, "-ALL")) {
  13170. X      if (!(sys.options & RELAXED_SYNTAX)) {
  13171. X    reject_mail (sender, request,
  13172. X             tsprintf ("Too many arguments to INDEX: %s\n\n\
  13173. XSyntax: index [archive | path-to-archive] [/password]\n", moreparams),
  13174. X             SYNTAX_ERROR, 0);
  13175. X    return;
  13176. X      }
  13177. X    }
  13178. X    else
  13179. X      all = TRUE;
  13180. X  if (archive[0] == EOS) /* Get archive */
  13181. X    strcpy (archive, DEFAULT_ARCHIVE);
  13182. X  sprintf (fullpath, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
  13183. X  strcpy (cur_archive, archive);
  13184. X  if ((slash = strchr (cur_archive, '/')))
  13185. X    *slash = EOS;
  13186. X#ifdef GO_INTERACTIVE
  13187. X  IN_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
  13188. X#endif
  13189. X  while (archive[0] != EOS) { /* Check all archives specified */
  13190. X    if ((master = fopen (fullpath, "r")) == NULL) {
  13191. X#ifdef GO_INTERACTIVE
  13192. X      OUT_OF_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
  13193. X#endif
  13194. X      NOTIFY_OF_BAD_ARCHIVE ("%s: Sorry, no index found.\n", cur_archive,
  13195. X                 BAD_ARCHIVE);
  13196. X      return;
  13197. X    }
  13198. X    found = FALSE;
  13199. X    while (!feof (master)) { /* Look at the current index for fullpath */
  13200. X      fullpath[0] = arch[0] = RESET (line);
  13201. X      fgets (line, MAX_LINE - 2, master);
  13202. X      if (line[0] != EOS) {
  13203. X        sscanf (line, "%s %s\n", arch, fullpath);
  13204. X        locase (arch);
  13205. X        if (!strcmp (arch, cur_archive)) {
  13206. X       found = TRUE;
  13207. X      break;
  13208. X        }
  13209. X      }
  13210. X    }
  13211. X    fclose (master);
  13212. X    if (!found) {
  13213. X#ifdef GO_INTERACTIVE
  13214. X      OUT_OF_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
  13215. X#endif
  13216. X      NOTIFY_OF_BAD_ARCHIVE ("%s: not a valid archive or path.\n", cur_archive,
  13217. X                 SYNTAX_ERROR);
  13218. X      return;
  13219. X    }
  13220. X    if ((slash = strchr (archive, '/')))
  13221. X      sprintf (archive, "%s", slash + 1); /* Move down the path */
  13222. X    else
  13223. X      sprintf (archive, "%s", archive + strlen (cur_archive));
  13224. X    strcpy (cur_archive, archive);
  13225. X    if ((slash = strchr (cur_archive, '/')))
  13226. X      *slash = EOS;
  13227. X    if (cur_archive[0] != EOS)
  13228. X      sprintf (fullpath, "%s/%s", fullpath, INDEX);
  13229. X  }
  13230. X  sscanf (params, "%s", archive);
  13231. X  sprintf (fullname, "%s/%s", fullpath, INDEX);
  13232. X  if ((index = fopen (fullname, "r")) == NULL) { /* Open index */
  13233. X#ifdef GO_INTERACTIVE
  13234. X    OUT_OF_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
  13235. X#endif
  13236. X    NOTIFY_OF_BAD_ARCHIVE ("Sorry, no index found in archive %s.\n", archive,
  13237. X               BAD_ARCHIVE);
  13238. X    return;
  13239. X  }
  13240. X  slash = request;
  13241. X  while ((slash = strchr (slash + 1, '/')) && !isspace (*(slash - 1)));
  13242. X  if (slash)
  13243. X    shadow_password (slash + 1);
  13244. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  13245. X         COPY_OWNER (ccindex), OK, FALSE, FALSE);
  13246. X  count = 0;
  13247. X  while (!feof (index)) { /* Echo archive; goto archive and get DIR file */
  13248. X    fullpath[0] = archive[0] = sys_password[0] = RESET (line);
  13249. X    fgets (line, MAX_LINE - 2, index);
  13250. X    if (line[0] != EOS) {
  13251. X      sscanf (line, "%s %s %s\n", archive, fullpath, sys_password);
  13252. X      upcase (sys_password);
  13253. X      fprintf (f, "\n%s: %s ", (!count ?  "Archive" : "Subarchive"), archive);
  13254. X      if (!strncmp (fullpath, ARCHIVE_DIR, strlen (ARCHIVE_DIR)))
  13255. X    fprintf (f, "(path: %s) ", fullpath + strlen (ARCHIVE_DIR) + 1);
  13256. X      if (!count || all) { /* List files for the top level archive only */
  13257. X    fprintf (f, "-- Files:\n");
  13258. X    if (sys_password[0] != EOS && strcmp (user_password, sys_password)) {
  13259. X      reply_code (RESTRICTED_REQ);
  13260. X      fprintf (f, "This archive requires special privileges for access.\n");
  13261. X      continue;
  13262. X    }
  13263. X    if (chdir (fullpath))
  13264. X      fprintf (f, "%s: Sorry, archive out of date.\n", archive);
  13265. X    else { /* Open DIR and get file names */
  13266. X      if ((dir = fopen (DIRF, "r")) == NULL)
  13267. X        reply_code (BAD_ARCHIVE),
  13268. X        fprintf (f, "Cannot obtain directory information.\n");
  13269. X      else {
  13270. X        while (!feof (dir)) {
  13271. X          line[0] = junk[0] = RESET (file);
  13272. X          fscanf (dir, "%s %d ", file, &parts);
  13273. X          if (file[0] != EOS) {
  13274. X        if (! (filesizes = (long int *) malloc (abs (parts) * sizeof (long int))))
  13275. X          report_progress (report, "\nIndex(): malloc() failed", TRUE),
  13276. X          gexit (11);
  13277. X        for (i = 0; i < abs (parts); i++)
  13278. X          fscanf (dir, "%ld ", filesizes + i);
  13279. X        fscanf (dir, "%s", junk);
  13280. X        header_printed = FALSE;
  13281. X        do { /* Get file description */
  13282. X          RESET (desc);
  13283. X          fgets (desc, MAX_LINE - 2, dir);
  13284. X          if (desc [0] != EOS && desc[strlen (desc) - 1] == '\n')
  13285. X            desc[strlen (desc) - 1] = EOS;
  13286. X          continued = FALSE;
  13287. X          if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
  13288. X            desc[strlen (desc) - 1] = EOS,
  13289. X            continued = TRUE;
  13290. X          if (file[0] != EOS) {
  13291. X            if (!header_printed) {
  13292. X              fprintf (f, "  %s (%d part%s", file, abs (parts),
  13293. X                   (abs (parts) > 1 ? "s" : ""));
  13294. X              for (i = 0; i < abs (parts); i++)
  13295. X            fprintf (f, ", %ld", *(filesizes + i));
  13296. X              fprintf (f, " bytes) %s", ((desc[0] != EOS) ? "--" : ""));
  13297. X              free ((long int *) filesizes);
  13298. X              header_printed = TRUE;
  13299. X            }
  13300. X            fprintf (f, "%s\n", desc);
  13301. X          }
  13302. X        } while (continued);
  13303. X          }
  13304. X        }
  13305. X        fclose (dir);
  13306. X      }
  13307. X    }
  13308. X      }
  13309. X      else
  13310. X    fprintf (f, "\n");
  13311. X    }
  13312. X    ++count;
  13313. X  }
  13314. X  fclose (index);
  13315. X#ifdef GO_INTERACTIVE
  13316. X  OUT_OF_CRITICAL_SECTION ("Index", SEM_ARCHIVES);
  13317. X#endif
  13318. X  COMPLETE_TELNET (f);
  13319. X  fclose (f);
  13320. X  DELIVER_MAIL (sender, COPY_OWNER (ccindex));
  13321. X}
  13322. X
  13323. X/*
  13324. X  Send the requested file from the specified archive. The file may have been
  13325. X  split in subparts, and in this case several emails will be sent -- one
  13326. X  for each part. The user may also obtain certain parts. A password is
  13327. X  required for obtaining files from a private archive.
  13328. X
  13329. X  Adapted USER CONTRIBUTED FUNCTION: Stefan Schroer.
  13330. X*/
  13331. X
  13332. Xvoid get (char *request, char *params, char *sender)
  13333. X{
  13334. X  FILE *f, *dir, *master;
  13335. X  char archive [MAX_LINE];
  13336. X  char arch [MAX_LINE];
  13337. X  char cur_archive [MAX_LINE];
  13338. X  char archive_orig [MAX_LINE];
  13339. X  char fullpath [MAX_LINE];
  13340. X  char moreparams [MAX_LINE];
  13341. X  char filename [MAX_LINE];
  13342. X  char fullname [MAX_LINE];
  13343. X  char dirpath [MAX_LINE];
  13344. X  char file [MAX_LINE];
  13345. X  char line [MAX_LINE];
  13346. X  char copy [MAX_LINE];
  13347. X  char sys_password [MAX_LINE];
  13348. X  char user_password [MAX_LINE];
  13349. X  char desc [MAX_LINE];
  13350. X  char subject [MAX_LINE];
  13351. X  char req [MAX_LINE];
  13352. X  char *slash, *uue_file = NULL, *s;
  13353. X  struct stat stat_buf;
  13354. X  int i, count = 0;
  13355. X  long int *filesizes;
  13356. X  BOOLEAN found, continued, compressed_source;
  13357. X
  13358. X  strcpy (req, request);
  13359. X  sprintf (request + strlen (request), "%s", params); /* Used as a subject */
  13360. X  archive[0] = fullpath[0] = fullname[0] = dirpath[0] =
  13361. X  filename[0] = cur_archive[0] = archive_orig[0] = sys.fax.fax_no [0] =
  13362. X    RESET (moreparams);
  13363. X  params [strlen (params) - 1] = EOS; /* Remove \n */
  13364. X  if (!strcmp (req, "FAX"))
  13365. X    fax_it = TRUE,
  13366. X    sscanf (params, "%s %s %s %s", sys.fax.fax_no, archive, filename,
  13367. X        moreparams);
  13368. X  else
  13369. X    fax_it = FALSE,
  13370. X    sscanf (params, "%s %s %s", archive, filename, moreparams);
  13371. X  strcpy (archive_orig, archive);
  13372. X  locase (archive);
  13373. X  locase (filename);
  13374. X  if (archive[0] == EOS || filename[0] == EOS ||
  13375. X      (fax_it && sys.fax.fax_no[0] == EOS)) { /* Missing args */
  13376. X    reject_mail (sender, request, tsprintf ("%s: missing arguments\n\n\
  13377. XSyntax: %s %s<archive | path-to-archive> <file> [/password] [parts]\n", req,
  13378. X         req, (fax_it ? "<fax-number> " : "")), SYNTAX_ERROR, 0);
  13379. X    fax_it = FALSE;
  13380. X    return;
  13381. X  }
  13382. X  if (moreparams[0] != EOS) { /* Specified password and/or parts to get */
  13383. X    if (moreparams[0] == '/') { /* Get password and any parts */
  13384. X      strcpy (user_password, moreparams);
  13385. X      strcpy (copy, user_password);
  13386. X      upcase (copy);
  13387. X      do {
  13388. X        sprintf (params, "%s", params + 1);
  13389. X      } while (strncmp (params, copy, strlen (copy)));
  13390. X      sprintf (params, "%s", params + strlen (copy));
  13391. X      RESET (moreparams);
  13392. X      sscanf (params, "%s", moreparams); /* Get parts */
  13393. X      if (moreparams[0] != EOS)
  13394. X        sprintf (params, "%s", strchr (params, moreparams[0]));
  13395. X      if (user_password[0] == '/') /* Remove leading '/' */
  13396. X        sprintf (user_password, "%s", user_password + 1);
  13397. X    }
  13398. X    else { /* No password given just parts */
  13399. X      strcpy (copy, filename);
  13400. X      upcase (copy);
  13401. X      do {
  13402. X        sprintf (params, "%s", params + 1);
  13403. X      } while (strncmp (params, copy, strlen (copy)));
  13404. X      sprintf (params, "%s", params + strlen (copy));
  13405. X      sprintf (params, "%s", strchr (params, moreparams[0]));
  13406. X    }
  13407. X  }
  13408. X  sprintf (fullpath, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
  13409. X  strcpy (cur_archive, archive);
  13410. X  if ((slash = strchr (cur_archive, '/')))
  13411. X    *slash = EOS;
  13412. X#ifdef GO_INTERACTIVE
  13413. X  IN_CRITICAL_SECTION ("get", SEM_ARCHIVES);
  13414. X#endif
  13415. X  while (archive[0] != EOS) { /* Check all archives specified */
  13416. X    if ((master = fopen (fullpath, "r")) == NULL) {
  13417. X#ifdef GO_INTERACTIVE
  13418. X      OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
  13419. X#endif
  13420. X      NOTIFY_OF_BAD_ARCHIVE ("%s: Sorry, no index found.\n", cur_archive,
  13421. X                 BAD_ARCHIVE);
  13422. X      fax_it = FALSE;
  13423. X      return;
  13424. X    }
  13425. X    found = FALSE;
  13426. X    while (!feof (master)) { /* Look at the current index for fullpath */
  13427. X      fullpath[0] = arch[0] = sys_password[0] = RESET (line);
  13428. X      fgets (line, MAX_LINE - 2, master);
  13429. X      if (line[0] != EOS) {
  13430. X        sscanf (line, "%s %s %s\n", arch, fullpath, sys_password);
  13431. X        locase (arch);
  13432. X    upcase (sys_password);
  13433. X        if (!strcmp (arch, cur_archive)) {
  13434. X          found = TRUE;
  13435. X          break;
  13436. X        }
  13437. X      }
  13438. X    }
  13439. X    fclose (master);
  13440. X    if (!found) {
  13441. X#ifdef GO_INTERACTIVE
  13442. X      OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
  13443. X#endif
  13444. X      NOTIFY_OF_BAD_ARCHIVE ("%s: not a valid archive or path.\n", cur_archive,
  13445. X                 SYNTAX_ERROR);
  13446. X      fax_it = FALSE;
  13447. X      return;
  13448. X    }
  13449. X    if ((slash = strchr (archive, '/')))
  13450. X      sprintf (archive, "%s", slash + 1); /* Move down the path */
  13451. X    else
  13452. X      sprintf (archive, "%s", archive + strlen (cur_archive));
  13453. X    strcpy (cur_archive, archive);
  13454. X    if ((slash = strchr (cur_archive, '/')))
  13455. X      *slash = EOS;
  13456. X    if (cur_archive[0] != EOS)
  13457. X      sprintf (fullpath, "%s/%s", fullpath, INDEX);
  13458. X  }
  13459. X
  13460. X
  13461. X  if (sys_password[0] != EOS && strcmp (user_password, sys_password)) {
  13462. X#ifdef GO_INTERACTIVE
  13463. X    OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
  13464. X#endif
  13465. X    NOTIFY_OF_BAD_ARCHIVE ("Sorry, archive %s requires special privileges \
  13466. Xfor obtaining files.\n", archive_orig, RESTRICTED_REQ);
  13467. X    fax_it = FALSE;
  13468. X    return;
  13469. X  }
  13470. X  sprintf (dirpath, "%s/%s", fullpath, DIRF);
  13471. X  if ((dir = fopen (dirpath, "r")) == NULL) { /* Dir archive */
  13472. X#ifdef GO_INTERACTIVE
  13473. X    OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
  13474. X#endif
  13475. X    NOTIFY_OF_BAD_ARCHIVE ("Unable to dir archive %s\n", archive_orig,
  13476. X               BAD_ARCHIVE);
  13477. X    fax_it = FALSE;
  13478. X    return;
  13479. X  }
  13480. X  found = FALSE;
  13481. X  while (!feof (dir)) { /* Get location and file-count of file to send */
  13482. X    file[0] = RESET (fullpath);
  13483. X    fscanf (dir, "%s %d ", file, &count);
  13484. X    if (! (filesizes = (long int *) malloc (abs (count) * sizeof (long int))))
  13485. X      report_progress (report, "\nget(): malloc() failed", TRUE),
  13486. X      gexit (11);
  13487. X    for (i = 0; i < abs (count); i++)
  13488. X      fscanf (dir, "%ld ", filesizes + i);
  13489. X    fscanf (dir, "%s", fullpath);
  13490. X    do { /* Get file description */
  13491. X      RESET (desc);
  13492. X      fgets (desc, MAX_LINE - 2, dir);
  13493. X      if (desc[0] != EOS && desc[strlen (desc) - 1] == '\n')
  13494. X        desc[strlen (desc) - 1] = EOS;
  13495. X      continued = FALSE;
  13496. X      if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
  13497. X        desc[strlen (desc) - 1] = EOS,
  13498. X        continued = TRUE;
  13499. X    } while (continued);
  13500. X    if (file[0] != EOS) {
  13501. X      locase (file);
  13502. X      if (!strcmp (filename, file)) {
  13503. X    found = TRUE;
  13504. X    break;
  13505. X      }
  13506. X    }
  13507. X  }
  13508. X  fclose (dir);
  13509. X  if (!found) {
  13510. X#ifdef GO_INTERACTIVE
  13511. X    OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
  13512. X#endif
  13513. X    NOTIFY_OF_BAD_ARCHIVE ("Sorry, file %s not found in specified archive.\n",
  13514. X               filename, SYNTAX_ERROR);
  13515. X    fax_it = FALSE;
  13516. X    return;
  13517. X  }
  13518. X  if (interactive) /* Empty out file */
  13519. X    create_header (&f, mailforwardf, sys.server.address, sender, subject,
  13520. X           COPY_OWNER (ccget), OK, FALSE, FALSE),
  13521. X    fclose (f);
  13522. X  for (i = 1; i <= abs (count); i++) { /* Send all parts of the file */
  13523. X    RESET (fullname);
  13524. X    if (abs (count) > 1)
  13525. X      sprintf (fullname, "%s/%s%d", fullpath, filename, i);
  13526. X    else
  13527. X      sprintf (fullname, "%s/%s", fullpath, filename);
  13528. X    if (moreparams[0] != EOS && !requested_part (params, i))
  13529. X      continue;
  13530. X    compressed_source = FALSE;
  13531. X    if (stat (fullname, &stat_buf)) {
  13532. X      strcat (fullname, ".Z"); /* Check for compressed file */
  13533. X      if (stat (fullname, &stat_buf)) {
  13534. X#ifdef GO_INTERACTIVE
  13535. X    OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
  13536. X#endif
  13537. X    NOTIFY_OF_BAD_ARCHIVE ("Sorry, file %s not found in specified \
  13538. Xarchive.\n", filename, BAD_ARCHIVE);
  13539. X    fax_it = FALSE;
  13540. X    return;
  13541. X      }
  13542. X      compressed_source = TRUE;
  13543. X    }
  13544. X    if (request [strlen (request) - 1] == '\n')
  13545. X      request [strlen (request) - 1] = EOS;
  13546. X    sprintf (subject, "%s (%d/%d)", request, i, abs (count));
  13547. X    if (!interactive) {
  13548. X      if (count < 0)
  13549. X    syscom ("%s %s | uuencode %s > %s",
  13550. X        (compressed_source ? "zcat" : "cat"), fullname, filename,
  13551. X        (uue_file = mystrdup (tmpnam (NULL)))),
  13552. X    compressed_source = FALSE,
  13553. X    strcpy (fullname, uue_file),
  13554. X    stat (fullname, &stat_buf),
  13555. X    *(filesizes + i - 1) = stat_buf.st_size;
  13556. X      slash = subject;
  13557. X      while ((slash = strchr (slash + 1, '/')) && !isspace (*(slash - 1)));
  13558. X      if (slash)
  13559. X    shadow_password (slash + 1);
  13560. X      {
  13561. X    long int offset = 0, cnt = 0, nbytes, nsubparts;
  13562. X    char _subject[MAX_LINE], _count[32], *part_copy = NULL;
  13563. X    FILE *file = NULL;
  13564. X    struct stat stat_buf;
  13565. X
  13566. X    if (sys.options & LIMIT_FILES) {
  13567. X      if (compressed_source)
  13568. X        part_copy = mystrdup (tmpnam (NULL)),
  13569. X        syscom ("zcat %s > %s", fullname, part_copy);
  13570. X      OPEN_FILE (file, (compressed_source ? part_copy : fullname), "r",
  13571. X             "get");
  13572. X      fstat (fileno (file), &stat_buf);
  13573. X    }
  13574. X    while (offset < *(filesizes + i - 1)) {
  13575. X      strcpy (_subject, subject);
  13576. X      if (sys.options & LIMIT_FILES &&
  13577. X          *(filesizes + i - 1) > sys.limits.files)
  13578. X         /* nsubparts could be inaccurate if during the process of looking
  13579. X        for the nearest newlines not beyond the limit, the total number
  13580. X        of bytes backtracked is an integer multiple of the limit; that
  13581. X        can be very frequent if the limit is too small */
  13582. X        nsubparts = (long int)
  13583. X          ceil ((float) *(filesizes + i - 1) / (float) sys.limits.files),
  13584. X        sprintf (_subject + strlen (_subject), " [%ld/%ld]", (++cnt),
  13585. X             nsubparts),
  13586. X        sprintf (_count, " (subpart %ld/%ld)", cnt, nsubparts);
  13587. X      create_header (&f, mailforwardf, sys.server.address, sender, _subject,
  13588. X             COPY_OWNER (ccget), OK, FALSE, FALSE);
  13589. X      fprintf (f, "Archive %s, file %s.\nPart %d/%d%s, \
  13590. Xtotal size %ld bytes:\n\n",
  13591. X           archive_orig, filename, i, abs (count), (cnt ? _count : ""),
  13592. X           *(filesizes + i - 1));
  13593. X      fprintf (f, "------------------------------ Cut here \
  13594. X------------------------------\n");
  13595. X      fclose (f);
  13596. X      if (sys.options & LIMIT_FILES) { /* Calculate nearest newline */
  13597. X        if (*(filesizes + i - 1) > sys.limits.files) {
  13598. X          nbytes = sys.limits.files;
  13599. X          fseek (file, (offset + nbytes - 1 < stat_buf.st_size ?
  13600. X                offset + nbytes - 1 : stat_buf.st_size - 1),
  13601. X             SEEK_SET);
  13602. X          while (fgetc (file) != '\n' && nbytes > 1)
  13603. X        --nbytes,
  13604. X        fseek (file, -2L, SEEK_CUR);
  13605. X          if (nbytes == 1)
  13606. X        nbytes = sys.limits.files;
  13607. X        }
  13608. X        else
  13609. X          nbytes = *(filesizes + i - 1);
  13610. X      }
  13611. X      else
  13612. X        nbytes = *(filesizes + i - 1);
  13613. X      CAT_FILE;
  13614. X      offset += nbytes;
  13615. X      echo_append ("------------------------------ Cut here \
  13616. X------------------------------", mailforwardf);
  13617. X      APPEND_TELNET ("get");
  13618. X      DELIVER_MAIL (sender, COPY_OWNER (ccget));
  13619. X    }
  13620. X    if (file) {
  13621. X      fclose (file);
  13622. X      if (part_copy)
  13623. X        unlink (part_copy),
  13624. X        free ((char *) part_copy);
  13625. X    }
  13626. X      }
  13627. X    }
  13628. X    else { /* Interactive */
  13629. X      if (fax_it)
  13630. X    cp (mailforwardf, ((s = mystrdup (tmpnam (NULL))))),
  13631. X    syscom ("%s < %s %s > /dev/null; rm -f %s &", sys.fax.prog, s,
  13632. X        sys.fax.fax_no, s),
  13633. X    free ((char *) s),
  13634. X    reply_code (OK);
  13635. X      else {
  13636. X    if (!strcmp (req, "GET"))
  13637. X      reply_code (WRITE_TO_FILE_ASC); /* Other modes possible */
  13638. X    else
  13639. X      reply_code (OK);
  13640. X    syscom ("%s %s >> %s", (compressed_source ? "zcat" : "cat"), fullname,
  13641. X        mailforwardf);
  13642. X      }
  13643. X    }
  13644. X    if (uue_file)
  13645. X      unlink (uue_file),
  13646. X      free ((char *) uue_file),
  13647. X      uue_file = NULL;
  13648. X  }
  13649. X#ifdef GO_INTERACTIVE
  13650. X  OUT_OF_CRITICAL_SECTION ("get", SEM_ARCHIVES);
  13651. X#endif
  13652. X  free ((long int *) filesizes);
  13653. X  fax_it = FALSE;
  13654. X}
  13655. X
  13656. X/*
  13657. X  Search the specified archive for matches of the supplied extended regular
  13658. X  expression.
  13659. X*/
  13660. X
  13661. Xvoid search (char *request, char *params, char *sender)
  13662. X{
  13663. X  FILE *f, *index, *dir, *master, *fp;
  13664. X  char archive [MAX_LINE];
  13665. X  char arch [MAX_LINE];
  13666. X  char cur_archive [MAX_LINE];
  13667. X  char line [MAX_LINE];
  13668. X  char file [MAX_LINE];
  13669. X  char _line [MAX_LINE];
  13670. X  char _line_copy [MAX_LINE];
  13671. X  char fullpath [MAX_LINE];
  13672. X  char regex [MAX_LINE];
  13673. X  char fullname [MAX_LINE];
  13674. X  char desc [MAX_LINE];
  13675. X  char junk [MAX_LINE];
  13676. X  char user_password [MAX_LINE];
  13677. X  char sys_password [MAX_LINE];
  13678. X  char arch_dir [MAX_LINE];
  13679. X  char *slash, *part_copy = NULL, *quote;
  13680. X  BOOLEAN continued, compressed_source, all, header_printed, found = FALSE;
  13681. X  int count, parts, i;
  13682. X  long int filesize;
  13683. X  struct stat stat_buf;
  13684. X
  13685. X  sprintf (request + strlen (request), "%s", params); /* Used as a subject */
  13686. X  archive[0] = fullpath[0] = fullname[0] = 
  13687. X  cur_archive[0] = RESET (regex);
  13688. X  sscanf (params, "%s %s", archive, user_password);
  13689. X  sscanf (original_params, "%s %s %s", junk, junk, regex);
  13690. X  if (archive[0] == EOS) {
  13691. X    reject_mail (sender, request, "SEARCH: missing arguments\n\n\
  13692. XSyntax: search <archive | path-to-archive> [/password] [-all] \
  13693. X<pattern>\n", SYNTAX_ERROR, 0);
  13694. X    fax_it = FALSE;
  13695. X    return;
  13696. X  }
  13697. X  locase (archive);
  13698. X  if (user_password[0] == '/') /* Remove leading '/' */
  13699. X    sprintf (user_password, "%s", user_password + 1);
  13700. X  else if (!strcmp (user_password, "-ALL"))
  13701. X    RESET (user_password),
  13702. X    all = TRUE,
  13703. X    sscanf (original_params, "%s %s %[^\n]", junk, junk, regex);
  13704. X  else
  13705. X    sscanf (original_params, "%s %[^\n]", junk, regex),
  13706. X    RESET (user_password);
  13707. X  if (regex[0] != EOS) {
  13708. X    part_copy = mystrdup (regex);
  13709. X    upcase (part_copy);
  13710. X    if (!strcmp (part_copy, "-ALL"))
  13711. X      all = TRUE,
  13712. X      sscanf (original_params, "%s %s %s %[^\n]", junk, junk, junk, regex);
  13713. X    else if (user_password[0] != EOS)
  13714. X      sscanf (original_params, "%s %s %[^\n]", junk, junk, regex);
  13715. X    free ((char *) part_copy);
  13716. X    part_copy = NULL;
  13717. X  }
  13718. X  else {
  13719. X    reject_mail (sender, request,
  13720. X         tsprintf ("Too few arguments to SEARCH\n\n\
  13721. XSyntax: search <archive | path-to-archive> [/password] [-all] <pattern>\n"),
  13722. X         SYNTAX_ERROR, 0);
  13723. X    return;
  13724. X  }
  13725. X  clean_request (regex);
  13726. X  if (regex[0] == '\'') {
  13727. X    sprintf (regex, "%s", regex + 1);
  13728. X    if (regex[0] == EOS || !re_strcmp ("'[ \t]*$", regex, NULL)) {
  13729. X      reject_mail (sender, request, "Mismatched or misplaced quotes\n",
  13730. X           SYNTAX_ERROR, 0);
  13731. X      return;
  13732. X    }
  13733. X    quote = strrchr (regex, '\'');
  13734. X    *quote = EOS;
  13735. X  }
  13736. X  else if (regex[0] == '\"') {
  13737. X    sprintf (regex, "%s", regex + 1);
  13738. X    if (regex[0] == EOS || !re_strcmp ("\"[ \t]*$", regex, NULL)) {
  13739. X      reject_mail (sender, request, "Mismatched or misplaced quotes\n",
  13740. X           SYNTAX_ERROR, 0);
  13741. X      return;
  13742. X    }
  13743. X    quote = strrchr (regex, '"');
  13744. X    *quote = EOS;
  13745. X  }
  13746. X  if (regex[0] == EOS) {
  13747. X    reject_mail (sender, request, "Empty regular expression\n", SYNTAX_ERROR, 0);
  13748. X    return;
  13749. X  }
  13750. X  if (re_strcmp (regex, "", NULL) < 0) {
  13751. X    reject_mail (sender, request, "Malformed regular expression\n",
  13752. X         SYNTAX_ERROR, 0);
  13753. X    return;
  13754. X  }
  13755. X  sprintf (fullpath, "%s/%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE, INDEX);
  13756. X  strcpy (cur_archive, archive);
  13757. X  if ((slash = strchr (cur_archive, '/')))
  13758. X    *slash = EOS;
  13759. X#ifdef GO_INTERACTIVE
  13760. X  IN_CRITICAL_SECTION ("search", SEM_ARCHIVES);
  13761. X#endif
  13762. X  while (archive[0] != EOS) { /* Check all archives specified */
  13763. X    if ((master = fopen (fullpath, "r")) == NULL) {
  13764. X#ifdef GO_INTERACTIVE
  13765. X      OUT_OF_CRITICAL_SECTION ("search", SEM_ARCHIVES);
  13766. X#endif
  13767. X      NOTIFY_OF_BAD_ARCHIVE ("%s: Sorry, no index found.\n", cur_archive,
  13768. X                 BAD_ARCHIVE);
  13769. X      return;
  13770. X    }
  13771. X    while (!feof (master)) { /* Look at the current index for fullpath */
  13772. X      fullpath[0] = arch[0] = RESET (line);
  13773. X      fgets (line, MAX_LINE - 2, master);
  13774. X      if (line[0] != EOS) {
  13775. X        sscanf (line, "%s %s\n", arch, fullpath);
  13776. X        locase (arch);
  13777. X        if (!strcmp (arch, cur_archive)) {
  13778. X       found = TRUE;
  13779. X      break;
  13780. X        }
  13781. X      }
  13782. X    }
  13783. X    fclose (master);
  13784. X    if (!found) {
  13785. X#ifdef GO_INTERACTIVE
  13786. X      OUT_OF_CRITICAL_SECTION ("search", SEM_ARCHIVES);
  13787. X#endif
  13788. X      NOTIFY_OF_BAD_ARCHIVE ("%s: not a valid archive or path.\n", cur_archive,
  13789. X                 SYNTAX_ERROR);
  13790. X      return;
  13791. X    }
  13792. X    if ((slash = strchr (archive, '/')))
  13793. X      sprintf (archive, "%s", slash + 1); /* Move down the path */
  13794. X    else
  13795. X      sprintf (archive, "%s", archive + strlen (cur_archive));
  13796. X    strcpy (cur_archive, archive);
  13797. X    if ((slash = strchr (cur_archive, '/')))
  13798. X      *slash = EOS;
  13799. X    if (cur_archive[0] != EOS)
  13800. X      sprintf (fullpath, "%s/%s", fullpath, INDEX);
  13801. X  }
  13802. X  sscanf (params, "%s", archive);
  13803. X  sprintf (fullname, "%s/%s", fullpath, INDEX);
  13804. X  if ((index = fopen (fullname, "r")) == NULL) { /* Open index */
  13805. X#ifdef GO_INTERACTIVE
  13806. X    OUT_OF_CRITICAL_SECTION ("search", SEM_ARCHIVES);
  13807. X#endif
  13808. X    NOTIFY_OF_BAD_ARCHIVE ("Sorry, no index found in archive %s.\n", archive,
  13809. X               BAD_ARCHIVE);
  13810. X    return;
  13811. X  }
  13812. X  slash = request;
  13813. X  while ((slash = strchr (slash + 1, '/')) && !isspace (*(slash - 1)));
  13814. X  if (slash)
  13815. X    shadow_password (slash + 1);
  13816. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  13817. X         COPY_OWNER (ccindex), OK, FALSE, FALSE);
  13818. X  fprintf (f, "Matches for pattern %s ...\n", regex);
  13819. X  locase (regex);
  13820. X  count = 0;
  13821. X  while (!feof (index)) { /* Echo archive; goto archive and get DIR file */
  13822. X    fullpath[0] = archive[0] = sys_password[0] = RESET (line);
  13823. X    fgets (line, MAX_LINE - 2, index);
  13824. X    if (line[0] != EOS) {
  13825. X      sscanf (line, "%s %s %s\n", archive, fullpath, sys_password);
  13826. X      upcase (sys_password);
  13827. X      if (!count || all) { /* Search files of the top level archive only */
  13828. X    fprintf (f, "\n%s: %s ", (!count ?  "--- Archive" : "--- Subarchive"),
  13829. X         archive);
  13830. X    if (!strncmp (fullpath, ARCHIVE_DIR, strlen (ARCHIVE_DIR)))
  13831. X      fprintf (f, "(path: %s) ", fullpath + strlen (ARCHIVE_DIR) + 1);
  13832. X    fprintf (f, "\n");
  13833. X    if (sys_password[0] != EOS && strcmp (user_password, sys_password)) {
  13834. X      reply_code (RESTRICTED_REQ);
  13835. X      fprintf (f, "This archive requires special privileges for access.\n");
  13836. X      continue;
  13837. X    }
  13838. X    if (chdir (fullpath))
  13839. X      fprintf (f, "%s: Sorry, archive out of date.\n", archive);
  13840. X    else { /* Open DIR and get file names */
  13841. X      if ((dir = fopen (DIRF, "r")) == NULL)
  13842. X        reply_code (BAD_ARCHIVE),
  13843. X        fprintf (f, "Cannot obtain directory information.\n");
  13844. X      else {
  13845. X        while (!feof (dir)) {
  13846. X          line[0] = junk[0] = RESET (file);
  13847. X          fscanf (dir, "%s %d ", file, &parts);
  13848. X          if (file[0] != EOS) {
  13849. X        for (i = 0; i < abs (parts); i++)
  13850. X          fscanf (dir, "%ld ", &filesize);
  13851. X        fscanf (dir, "%s", arch_dir);
  13852. X        do { /* Get file description */
  13853. X          RESET (desc);
  13854. X          fgets (desc, MAX_LINE - 2, dir);
  13855. X          if (desc [0] != EOS && desc[strlen (desc) - 1] == '\n')
  13856. X            desc[strlen (desc) - 1] = EOS;
  13857. X          continued = FALSE;
  13858. X          if (desc[0] != EOS && desc[strlen (desc) - 1] == '\\')
  13859. X            desc[strlen (desc) - 1] = EOS,
  13860. X            continued = TRUE;
  13861. X        } while (continued);
  13862. X        if (parts > 0) { /* Binaries are not searched */
  13863. X          for (i = 0; i < parts; i++) {
  13864. X            RESET (fullname);
  13865. X            if (parts > 1)
  13866. X              sprintf (fullname, "%s/%s%d", arch_dir, file, i);
  13867. X            else
  13868. X              sprintf (fullname, "%s/%s", arch_dir, file);
  13869. X            compressed_source = FALSE;
  13870. X            if (stat (fullname, &stat_buf)) {
  13871. X              strcat (fullname, ".Z"); /* Check for compressed file */
  13872. X              if (stat (fullname, &stat_buf))
  13873. X            continue; /* Error in archive */
  13874. X              compressed_source = TRUE;
  13875. X            }
  13876. X            if (compressed_source)
  13877. X              part_copy = mystrdup (tmpnam (NULL)),
  13878. X              syscom ("zcat %s > %s", fullname, part_copy);
  13879. X            OPEN_FILE (fp, (compressed_source ? part_copy :
  13880. X                    fullname), "r", "search");
  13881. X            header_printed = FALSE;
  13882. X            while (!feof (fp)) {
  13883. X              RESET (_line);
  13884. X              fgets (_line, MAX_LINE - 2, fp);
  13885. X              strcpy (_line_copy, _line);
  13886. X              if (_line_copy[0] != EOS &&
  13887. X              _line_copy[strlen (_line_copy) - 1] == '\n')
  13888. X            _line_copy[strlen (_line_copy) - 1] = EOS;
  13889. X              locase (_line);
  13890. X              if (_line[0] != EOS &&
  13891. X              re_strcmp (regex, _line, NULL) > 0) {
  13892. X            if (!header_printed)
  13893. X              if (parts > 1)
  13894. X                fprintf (f, "\n>>> File %s, part %d:\n", file, i);
  13895. X              else
  13896. X                fprintf (f, "\n>>> File %s:\n", file);
  13897. X            fprintf (f, "%s\n", _line_copy);
  13898. X            header_printed = TRUE;
  13899. X              }
  13900. X            }
  13901. X            if (header_printed)
  13902. X              fprintf (f, "<<< End of matches in file %s\n", file);
  13903. X            fclose (fp);
  13904. X            if (part_copy)
  13905. X              unlink (part_copy),
  13906. X              free ((char *) part_copy),
  13907. X              part_copy = NULL;
  13908. X          }
  13909. X        }
  13910. X          }
  13911. X        }
  13912. X        fclose (dir);
  13913. X      }
  13914. X    }
  13915. X      }
  13916. X    }
  13917. X    ++count;
  13918. X  }
  13919. X  fclose (index);
  13920. X#ifdef GO_INTERACTIVE
  13921. X  OUT_OF_CRITICAL_SECTION ("search", SEM_ARCHIVES);
  13922. X#endif
  13923. X  COMPLETE_TELNET (f);
  13924. X  fclose (f);
  13925. X  DELIVER_MAIL (sender, COPY_OWNER (ccindex));
  13926. X}
  13927. X
  13928. X/*
  13929. X  Give specific information about this release.
  13930. X*/
  13931. X
  13932. Xvoid release (char *request, char *params, char *sender)
  13933. X{
  13934. X  char param [MAX_LINE];
  13935. X  FILE *f;
  13936. X
  13937. X  sprintf (request + strlen (request), "%s", params); /* Used as a subject */
  13938. X  RESET (param);
  13939. X  sscanf (params, "%s", param);
  13940. X  if (param[0] != EOS && !(sys.options & RELAXED_SYNTAX)) {
  13941. X    reject_mail (sender, request, tsprintf ("Invalid RELEASE option%s\n\
  13942. XSyntax: release\n", params), SYNTAX_ERROR, 0);
  13943. X    return;
  13944. X  }
  13945. X  create_header (&f, mailforwardf, sys.server.address, sender, request,
  13946. X         COPY_OWNER (ccrelease), OK, FALSE, FALSE);
  13947. X  fprintf (f, "ListProcessor, version %s\nRevision level: %s\n", VERSION,
  13948. X       REV_LEVEL);
  13949. X  fprintf (f, "Last update: %s\nManager: %s\nListProcessor address: %s\n",
  13950. X       UPDATE_DATE, sys.manager, sys.server.address);
  13951. X  COMPLETE_TELNET (f);
  13952. X  fclose (f);
  13953. X  DELIVER_MAIL (sender, COPY_OWNER (ccrelease));
  13954. X}
  13955. X
  13956. X/*
  13957. X  Forward a 'request' to all servers handling peer lists.
  13958. X*/
  13959. X
  13960. Xvoid notify_peer_servers (char *file, char *request, char *params, char *sender)
  13961. X{
  13962. X  FILE *f, *mail;
  13963. X  char *mail_method;
  13964. X  char email [MAX_LINE];
  13965. X  char mode [MAX_LINE];
  13966. X  char alias [MAX_LINE];
  13967. X  char listproc [MAX_LINE];
  13968. X  char servers [MAX_LINE];
  13969. X  char subject [MAX_LINE];
  13970. X  char *file_tmp = mystrdup (tmpnam (NULL));
  13971. X
  13972. X  if (peer_server_request || do_not_notify_peer_server)
  13973. X    return;
  13974. X#ifdef GO_INTERACTIVE
  13975. X  IN_CRITICAL_SECTION ("notify_peer_servers", SEM_LISTFILES);
  13976. X#endif
  13977. X  cp (file, file_tmp);
  13978. X#ifdef GO_INTERACTIVE
  13979. X  OUT_OF_CRITICAL_SECTION ("notify_peer_servers", SEM_LISTFILES);
  13980. X#endif
  13981. X  OPEN_FILE (f, file_tmp, "r", "notify_peer_servers");
  13982. X  sprintf (subject, "%s %s", PEER_SERVER_REQUEST, sys.server.address);
  13983. X  RESET (servers);
  13984. X  if (sys.options & USE_ENV_VAR) {
  13985. X    if ((mail_method = (char *) malloc ((10 + strlen (sys.mail.env_var) +
  13986. X                     strlen (sender) +
  13987. X                     strlen (sys.mail.mail_prog))
  13988. X                    * sizeof (char))) == NULL)
  13989. X      report_progress (report, "\nnotify_peer_servers(): malloc() failed",
  13990. X               TRUE),
  13991. X      gexit (11);
  13992. X    sprintf (mail_method, "env - %s=%s %s ", sys.mail.env_var,
  13993. X         sender, sys.mail.mail_prog);
  13994. X  }
  13995. X  else {
  13996. X    if ((mail_method = (char *) malloc ((strlen (sys.mail.method) + 1) 
  13997. X                    * sizeof (char))) == NULL)
  13998. X      report_progress (report, "\nnotify_peer_servers(): malloc() failed",
  13999. X               TRUE),
  14000. X      gexit (11);
  14001. X    strcpy (mail_method, sys.mail.method);
  14002. X  }
  14003. X  while (!feof (f)) {
  14004. X    email[0] = mode[0] = alias[0] = RESET (listproc);
  14005. X    fscanf (f, "%s %s %s %s\n", email, mode, alias, listproc);
  14006. X    if (email[0] != EOS) { /* Send mail to peer server */
  14007. X      sprintf (servers + strlen (servers), "%s\n", listproc);
  14008. X      create_header (&mail, mailforwardf, sender, listproc, 
  14009. X             subject, FALSE, OK, FALSE, FALSE);
  14010. X      fprintf (mail, "%s %s %s\n", request, alias, params);
  14011. X      COMPLETE_TELNET (mail);
  14012. X      fclose (mail);
  14013. X      if (sys.options & USE_SYSMAIL)
  14014. X    sysmail (mailforwardf);
  14015. X      else
  14016. X    syscom ("%s '%s' < %s", mail_method,
  14017. X        (((sys.options & USE_TELNET) == 0) ? locase (listproc) : " "),
  14018. X        mailforwardf);
  14019. X    }
  14020. X  }
  14021. X  if (servers[0] != EOS) { /* Notify sender as well */
  14022. X    create_header (&mail, mailforwardf, sys.server.address, sender, 
  14023. X           tsprintf ("Notification from %s", sys.server.address),
  14024. X           FALSE, OK, FALSE, FALSE);
  14025. X    fprintf (mail, "%s: Your request has been forwarded to the following peer \
  14026. Xservers,\nwho will forward you with a copy of their own results:\n\n%s", 
  14027. Xupcase (request), servers);
  14028. X    COMPLETE_TELNET (mail);
  14029. X    fclose (mail);
  14030. X    if (sys.options & USE_SYSMAIL)
  14031. X      sysmail (mailforwardf);
  14032. X    else
  14033. X      syscom ("%s %s < %s", mail_method,
  14034. X          (((sys.options & USE_TELNET) == 0) ? locase (sender) : ""),
  14035. X          mailforwardf);
  14036. X  }
  14037. X  unlink (file_tmp);
  14038. X  free ((char *) file_tmp);
  14039. X  free ((char *) mail_method);
  14040. X  fclose (f);
  14041. X}
  14042. X
  14043. X/*
  14044. X  Internal request generated by catmail; the text that follows is sent
  14045. X  to 'sender'. This request is generated only for moderated lists.
  14046. X*/
  14047. X
  14048. Xvoid notify (char *request, char *params, char *sender)
  14049. X{
  14050. X  FILE *f;
  14051. X  char line [MAX_LINE];
  14052. X
  14053. X  create_header (&f, mailforwardf, sys.server.address, sender, "Notification",
  14054. X         FALSE, OK, FALSE, FALSE);
  14055. X  RESET (line);
  14056. X  while (!feof (mail) && /* Copy till eof or next message */
  14057. X     (strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE))))
  14058. X    fputs (line, f),
  14059. X    RESET (line),
  14060. X    fgets (line, MAX_LINE - 2, mail);
  14061. X  COMPLETE_TELNET (f);
  14062. X  fclose (f);
  14063. X  DELIVER_MAIL (sender, FALSE);
  14064. X  if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))
  14065. X    fseek (mail, -strlen (line), SEEK_CUR); /* Move back to beginning */
  14066. X}
  14067. X
  14068. X/*
  14069. X  Approve a message for a moderated list. The owner has supplied message
  14070. X  a tag for a message approved, so look for it in the moderated file,
  14071. X  and append it to the mail file, then remove it from the moderated file.
  14072. X*/
  14073. X
  14074. Xvoid approve (char *request, char *params, char *sender)
  14075. X{
  14076. X  char password [MAX_LINE];
  14077. X  char req [MAX_LINE];
  14078. X  char line [MAX_LINE];
  14079. X  char prev_line [MAX_LINE];
  14080. X  char moreparams [MAX_LINE];
  14081. X  char match [MAX_LINE];
  14082. X  FILE *f, *moderated, *mail;
  14083. X  int lfd = 2, lfd2 = 2, tag, tag_to_approve = 0;
  14084. X  long int sig_mask;
  14085. X  BOOLEAN copy = FALSE;
  14086. X
  14087. X  moreparams[0] = req[0] = RESET (password);
  14088. X  strcpy (req, request);
  14089. X  sscanf (params, "%s %d %s", password, &tag_to_approve, moreparams);
  14090. X  shadow_password (params);
  14091. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  14092. X       params);
  14093. X  if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
  14094. X    NOT_LIST_OWNER; /* Hacker attack */
  14095. X    return;
  14096. X  }
  14097. X  if (password[0] == EOS) {
  14098. X    reject_mail (sender, request,
  14099. X         tsprintf ("Missing password for %s request\n\n\
  14100. XSyntax: approve <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
  14101. X    return;
  14102. X  }
  14103. X  if (strcmp (password, sys.lists[listid].password)) {
  14104. X    reject_mail (sender, request,
  14105. X         tsprintf ("Invalid password for %s request\n", req),
  14106. X         SYNTAX_ERROR, 0);
  14107. X    return;
  14108. X  }
  14109. X  if (tag_to_approve == 0) {
  14110. X    reject_mail (sender, request,
  14111. X         tsprintf ("Invalid or missing tag number for %s request\n\n\
  14112. XSyntax: approve <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
  14113. X    return;
  14114. X  }
  14115. X  if (moreparams[0] != EOS) {
  14116. X    reject_mail (sender, request,
  14117. X         tsprintf ("Too many tag numbers to %s request\n\n\
  14118. XSyntax: approve <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
  14119. X    return;
  14120. X  }
  14121. X#ifndef NO_LOCKS
  14122. X  if ((lfd = lock_file (list_mail_f, O_RDWR | O_CREAT, 416, TRUE)) < 0)
  14123. X    switch (lfd) {
  14124. X    case CANT_OPEN:
  14125. X      CANNOT_STAT_FILE (list_mail_f, "open");
  14126. X      report_progress (report, 
  14127. X               tsprintf ("\nCould not stat file %s", list_mail_f),
  14128. X               TRUE);
  14129. X      gexit (1);
  14130. X    case CANT_LOCK:
  14131. X      CANNOT_STAT_FILE (list_mail_f, "lock");
  14132. X      return;
  14133. X    }
  14134. X  if ((lfd2 = lock_file (list_moderated_f, O_RDWR | O_CREAT, 416, TRUE)) < 0)
  14135. X    switch (lfd2) {
  14136. X    case CANT_OPEN:
  14137. X      CANNOT_STAT_FILE (list_moderated_f, "open");
  14138. X      report_progress (report,
  14139. X               tsprintf ("\nCould not stat file %s", list_moderated_f),
  14140. X               TRUE);
  14141. X      gexit (1);
  14142. X    case CANT_LOCK:
  14143. X      unlock_file (lfd);
  14144. X      CANNOT_STAT_FILE (list_moderated_f, "lock");
  14145. X      return;
  14146. X    }
  14147. X#endif
  14148. X#ifdef bsd
  14149. X  sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  14150. X#elif defined (svr4) || defined (svr3)
  14151. X  sighold (SIGINT);
  14152. X  sighold (SIGTERM);
  14153. X#endif
  14154. X  OPEN_FILE (moderated, list_moderated_f, "r", "approve");
  14155. X  OPEN_FILE (mail, list_mail_f, "a", "approve");
  14156. X  prev_line[0] = RESET (line);
  14157. X  while (!feof (moderated)) {
  14158. X    if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)) &&
  14159. X    copy)
  14160. X      break; /* We are at the beginning of another message; stop copying */
  14161. X    strcpy (match, "\\1");
  14162. X    if (re_strcmp (MESSAGE_TAG, line, match) > 0)  { /* Get tag # */
  14163. X      sprintf (line, "%s", line + strlen (match));
  14164. X      sscanf (line, "%d", &tag);
  14165. X      RESET (line); /* Blow away Message-Tag: */
  14166. X      if (tag_to_approve == tag)
  14167. X    copy = TRUE;
  14168. X    }
  14169. X    if (copy && prev_line[0] != EOS)
  14170. X      fprintf (mail, "%s", prev_line);
  14171. X    strcpy (prev_line, line);
  14172. X    RESET (line);
  14173. X    fgets (line, MAX_LINE - 2, moderated);
  14174. X  }
  14175. X  if (copy && prev_line[0] != EOS)
  14176. X    fprintf (mail, "%s", prev_line);
  14177. X  fclose (moderated);
  14178. X  fclose (mail);
  14179. X  if (!copy) { /* Message to be approved not found */
  14180. X    NO_SUCH_MESSAGE_TAG (tag_to_approve);
  14181. X    goto abort;
  14182. X  }
  14183. X  remove_msg (list_moderated_f, tag_to_approve, report);
  14184. X#ifdef bsd
  14185. X  sigsetmask (sig_mask);
  14186. X#elif defined (svr4) || defined (svr3)
  14187. X  sigrelse (SIGINT);
  14188. X  sigrelse (SIGTERM);
  14189. X#endif
  14190. X  create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  14191. X         OK, FALSE, FALSE);
  14192. X  fprintf (f, "Your request was successfully completed.\n");
  14193. X  COMPLETE_TELNET (f);
  14194. X  fclose (f);
  14195. X  DELIVER_MAIL (sender, FALSE);
  14196. X  abort: ;
  14197. X#ifndef NO_LOCKS
  14198. X  unlock_file (lfd);
  14199. X  unlock_file (lfd2);
  14200. X#endif
  14201. X}
  14202. X
  14203. X/*
  14204. X  Discard a message from a moderated list.
  14205. X*/
  14206. X
  14207. Xvoid discard (char *request, char *params, char *sender)
  14208. X{
  14209. X  char password [MAX_LINE];
  14210. X  char req [MAX_LINE];
  14211. X  char moreparams [MAX_LINE];
  14212. X  FILE *f;
  14213. X  int tag_to_discard = 0, lfd = 2;
  14214. X  long int sig_mask;
  14215. X
  14216. X  moreparams[0] = req[0] = RESET (password);
  14217. X  strcpy (req, request);
  14218. X  sscanf (params, "%s %d %s", password, &tag_to_discard, moreparams);
  14219. X  shadow_password (params);
  14220. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  14221. X           params);
  14222. X  if (!owner_listed (OWNERSF, sender, sys.lists[listid].alias, report)) {
  14223. X    NOT_LIST_OWNER; /* Hacker attack */
  14224. X    return;
  14225. X  }
  14226. X  if (password[0] == EOS) {
  14227. X    reject_mail (sender, request, tsprintf ("Missing password for %s request\n\n\
  14228. XSyntax: discard <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
  14229. X    return;
  14230. X  }
  14231. X  if (strcmp (password, sys.lists[listid].password)) {
  14232. X    reject_mail (sender, request,
  14233. X         tsprintf ("Invalid password for %s request\n", req),
  14234. X         SYNTAX_ERROR, 0);
  14235. X    return;
  14236. X  }
  14237. X  if (tag_to_discard == 0) {
  14238. X    reject_mail (sender, request,
  14239. X         tsprintf ("Invalid or missing tag number for %s request\n\n\
  14240. XSyntax: discard <list> <password> <tag>\n", req),
  14241. X         SYNTAX_ERROR, 0);
  14242. X    return;
  14243. X  }
  14244. X  if (moreparams[0] != EOS) {
  14245. X    reject_mail (sender, request,
  14246. X         tsprintf ("Too many tag numbers to %s request\n\n\
  14247. XSyntax: discard <list> <password> <tag>\n", req), SYNTAX_ERROR, 0);
  14248. X    return;
  14249. X  }
  14250. X#ifndef NO_LOCKS
  14251. X  if ((lfd = lock_file (list_moderated_f, O_RDWR | O_CREAT, 416, TRUE)) < 0)
  14252. X    switch (lfd) {
  14253. X    case CANT_OPEN:
  14254. X      CANNOT_STAT_FILE (list_moderated_f, "open");
  14255. X      report_progress (report,
  14256. X               tsprintf ("\nCould not stat file %s", list_moderated_f),
  14257. X               TRUE);
  14258. X      gexit (1);
  14259. X    case CANT_LOCK:
  14260. X      CANNOT_STAT_FILE (list_moderated_f, "lock");
  14261. X      return;
  14262. X    }
  14263. X#endif
  14264. X#ifdef bsd
  14265. X  sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  14266. X#elif defined (svr4) || defined (svr3)
  14267. X  sighold (SIGINT);
  14268. X  sighold (SIGTERM);
  14269. X#endif
  14270. X  if (!remove_msg (list_moderated_f, tag_to_discard, report)) {
  14271. X#ifdef bsd
  14272. X    sigsetmask (sig_mask);
  14273. X#elif defined (svr4) || defined (svr3)
  14274. X    sigrelse (SIGINT);
  14275. X    sigrelse (SIGTERM);
  14276. X#endif
  14277. X    NO_SUCH_MESSAGE_TAG (tag_to_discard);
  14278. X    goto abort;
  14279. X  }
  14280. X#ifdef bsd
  14281. X  sigsetmask (sig_mask);
  14282. X#elif defined (svr4) || defined (svr3)
  14283. X  sigrelse (SIGINT);
  14284. X  sigrelse (SIGTERM);
  14285. X#endif
  14286. X  create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  14287. X         OK, FALSE, FALSE);
  14288. X  fprintf (f, "Your request was successfully completed.\n");
  14289. X  COMPLETE_TELNET (f);
  14290. X  fclose (f);
  14291. X  DELIVER_MAIL (sender, FALSE);
  14292. X  abort: ;
  14293. X#ifndef NO_LOCKS
  14294. X  unlock_file (lfd);
  14295. X#endif
  14296. X}
  14297. X
  14298. X/*
  14299. X  Execute a program and reply with the output from stdout and stderr.
  14300. X*/
  14301. X
  14302. Xvoid execute (char *request, char *params, char *sender)
  14303. X{
  14304. X  char password [MAX_LINE];
  14305. X  char req [MAX_LINE];
  14306. X  char sstdout [MAX_LINE];
  14307. X  char sstderr [MAX_LINE];
  14308. X  char *prog = NULL;
  14309. X  FILE *f;
  14310. X  struct stat stat_buf;
  14311. X
  14312. X  req[0] = RESET (password);
  14313. X  strcpy (req, request);
  14314. X  sscanf (params, "%s ", password);
  14315. X  shadow_password (original_params);
  14316. X  sprintf (request + strlen (request), "%s", original_params);
  14317. X  if (password[0] == EOS) {
  14318. X    reject_mail (sender, request,
  14319. X         tsprintf ("Missing password for %s request\n\n\
  14320. XSyntax: execute <password> #<prog> [args]\n", req), SYNTAX_ERROR, 0);
  14321. X    return;
  14322. X  }
  14323. X  if (strcmp (password, sys.server.password)) {
  14324. X    reject_mail (sender, request, tsprintf ("Invalid password for %s request\n",
  14325. X                        req), SYNTAX_ERROR, 0);
  14326. X    return;
  14327. X  }
  14328. X  if ((prog = strchr (original_params, '#')) == NULL) {
  14329. X    reject_mail (sender, request,
  14330. X         tsprintf ("Missing '#' for %s request\n\n\
  14331. XSyntax: execute <password> #<prog> [args]\n", req), SYNTAX_ERROR, 0);
  14332. X    return;
  14333. X  }
  14334. X  original_params [strlen (original_params) - 1] = EOS; /* Remove \n */
  14335. X  sprintf (sstdout, "%s.%d", STDOUT, getpid());
  14336. X  sprintf (sstderr, "%s.%d", STDERR, getpid());
  14337. X  syscom ("%s > %s 2> %s", prog + 1, sstdout, sstderr);
  14338. X  create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  14339. X         OK, FALSE, FALSE);
  14340. X  if (!stat (sstdout, &stat_buf) && stat_buf.st_size > 0) {
  14341. X    fprintf (f, "Output from stdout:\n");
  14342. X    fclose (f);
  14343. X    cat_append (sstdout, mailforwardf);
  14344. X    APPEND_TELNET ("execute");
  14345. X    DELIVER_MAIL (sender, FALSE);
  14346. X  }
  14347. X  if (!stat (sstderr, &stat_buf) && stat_buf.st_size > 0) {
  14348. X    if (interactive) /* In case execute is ever allowed for live connections */
  14349. X      if (stat (sstdout, &stat_buf))
  14350. X    create_header (&f, mailforwardf, sys.server.address, sender, request,
  14351. X               FALSE, OK, FALSE, FALSE);
  14352. X      else
  14353. X    f = fopen (mailforwardf, "a");
  14354. X    else
  14355. X      create_header (&f, mailforwardf, sys.server.address, sender, request,
  14356. X             FALSE, OK, FALSE, FALSE);
  14357. X    fprintf (f, "Output from stderr:\n");
  14358. X    fclose (f);
  14359. X    cat_append (sstderr, mailforwardf);
  14360. X    APPEND_TELNET ("execute");
  14361. X    DELIVER_MAIL (sender, FALSE);
  14362. X  }
  14363. X  unlink (sstdout);
  14364. X  unlink (sstderr);
  14365. X}
  14366. X
  14367. X/*
  14368. X  Execute a UNIX command allowed for the specified list by members of the list,
  14369. X  and receive the output from stdout and/or stderr.
  14370. X*/
  14371. X
  14372. Xvoid unix_cmd (char *request, char *params, char *sender)
  14373. X{
  14374. X  char password [MAX_LINE];
  14375. X  char req [MAX_LINE];
  14376. X  char sstdout [MAX_LINE];
  14377. X  char sstderr [MAX_LINE];
  14378. X  char prog [10240], *_prog, *args [10], *blank;
  14379. X  FILE *f;
  14380. X  struct stat stat_buf;
  14381. X  _CMDS *unix_cmd = sys.lists[listid].unix_cmds;
  14382. X  int nargs;
  14383. X  long int sig_mask;
  14384. X
  14385. X  if (matched_rlists) { /* Request for a remote list; notify sender */
  14386. X    NOTIFY_OF_REQUEST_FORWARDING;
  14387. X    FORWARD_REQUEST;
  14388. X    return;
  14389. X  }
  14390. X  req[0] = RESET (password);
  14391. X  strcpy (req, request);
  14392. X  sscanf (params, "%s ", password);
  14393. X  _prog = original_params;
  14394. X  while (*_prog != EOS && isspace (*_prog))    /* Skip over list */
  14395. X    ++_prog;
  14396. X  while (*_prog != EOS && !isspace (*_prog))    /* Get to password */
  14397. X    ++_prog;
  14398. X  shadow_password (_prog);
  14399. X  sprintf (request + strlen (request), " %s%s", sys.lists[listid].alias,
  14400. X           _prog);
  14401. X  if (subscribed (report, sender, subscribersf, NULL, NULL,
  14402. X          aliasesf, TRUE) == NOTSUBSCRIBED) {
  14403. X    MEMBERS_ONLY;
  14404. X    return;
  14405. X  }
  14406. X  if (password[0] == EOS) {
  14407. X    create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  14408. X           OK, FALSE, FALSE);
  14409. X    fprintf (f, "You may run the following commands:\n\n");
  14410. X    while (unix_cmd)
  14411. X      fprintf (f, "%s (%s)\n", unix_cmd->name, unix_cmd->comment),
  14412. X      unix_cmd = unix_cmd->next;
  14413. X    COMPLETE_TELNET (f);
  14414. X    fclose (f);
  14415. X    DELIVER_MAIL (sender, FALSE);
  14416. X    return;
  14417. X  }
  14418. X  if (!sys.lists[listid].unix_cmds) {
  14419. X    reject_mail (sender, request, tsprintf ("No commands to execute for %s \
  14420. Xrequest\n", req), SYNTAX_ERROR, 0);
  14421. X    return;
  14422. X  }
  14423. X  if ((blank = strchr (original_params, '`')) ||
  14424. X      (blank = strchr (original_params, '|')) ||
  14425. X      (blank = strchr (original_params, '<')) ||
  14426. X      (blank = strchr (original_params, '>')) ||
  14427. X      (blank = strchr (original_params, ':'))) {
  14428. X    reject_mail (sender, request,
  14429. X         tsprintf ("Invalid character %c in request.\n", *blank),
  14430. X         SYNTAX_ERROR, 0);
  14431. X    return;
  14432. X  }
  14433. X  clean_request (_prog); /* Skip leading blanks */
  14434. X  while (*_prog != EOS && *_prog == 'X') ++_prog;
  14435. X  clean_request (_prog); /* Skip leading blanks */
  14436. X  if (*_prog == EOS) {
  14437. X    reject_mail (sender, request, tsprintf ("Missing command to run for %s \
  14438. Xrequest\n\n\
  14439. XSyntax: run <list> [<password> <cmd> [args]]\n", req), SYNTAX_ERROR, 0);
  14440. X    return;
  14441. X  }
  14442. X  memset ((char *) prog, EOS, 10240);
  14443. X  sscanf (_prog, "%s ", prog);
  14444. X  upcase (prog);
  14445. X  while (unix_cmd) {
  14446. X    if (!strcmp (unix_cmd->name, prog)) {
  14447. X      if (strcmp (password, unix_cmd->password)) {
  14448. X    reject_mail (sender, request, tsprintf ("Invalid password for %s request\n",
  14449. X                        req), SYNTAX_ERROR, 0);
  14450. X    return;
  14451. X      }
  14452. X      strcpy (prog, unix_cmd->cmd);
  14453. X      break;
  14454. X    }
  14455. X    unix_cmd = unix_cmd->next;
  14456. X  }
  14457. X  if (!unix_cmd) {
  14458. X    reject_mail (sender, request, tsprintf ("Unknown command %s\n", prog),
  14459. X         SYNTAX_ERROR, 0);
  14460. X    return;
  14461. X  }
  14462. X  original_params [strlen (original_params) - 1] = EOS; /* Remove \n */
  14463. X  while (*_prog != EOS && isspace (*_prog))    /* Skip over cmd */
  14464. X    ++_prog;
  14465. X  while (*_prog != EOS && !isspace (*_prog))    /* Get to arguments */
  14466. X    ++_prog;
  14467. X  while (*_prog != EOS && isspace (*_prog))
  14468. X    ++_prog;
  14469. X  nargs = 0;
  14470. X  while (*_prog != EOS && nargs < 9) {
  14471. X    if (!(args[nargs] = (char *) malloc ((strlen (_prog) + 1) * sizeof (char))))
  14472. X      report_progress (report, "\nunix_cmd(): malloc() failed", TRUE),
  14473. X      gexit (11);
  14474. X    strcpy (args[nargs], _prog);
  14475. X    if ((blank = strchr (args[nargs], ' ')) || 
  14476. X    (blank = strchr (args[nargs], '\t')))
  14477. X      *blank = EOS;
  14478. X    ++nargs;
  14479. X    while (*_prog != EOS && !isspace (*_prog))
  14480. X      ++_prog;
  14481. X    while (*_prog != EOS && isspace (*_prog))    /* Get to next arg */
  14482. X      ++_prog;
  14483. X  }
  14484. X  _prog = prog;
  14485. X  while (*_prog != EOS && (_prog = strchr (_prog, '$')))
  14486. X    if (*(_prog + 1) == '*')     /* Insert all user arguments */
  14487. X    _prog += insert_word (_prog, args, nargs, 0, 2);
  14488. X    else if (isdigit (*(_prog + 1)) && *(_prog + 1) > '0')
  14489. X    _prog += insert_word (_prog, args, 1, (int) *(_prog + 1) - '0' - 1, 2);
  14490. X    else
  14491. X      ++_prog;
  14492. X  while (nargs)
  14493. X    free ((char *) args[--nargs]);
  14494. X#ifdef bsd
  14495. X    sig_mask = sigblock (sigmask (SIGINT) | sigmask (SIGTERM));
  14496. X#elif defined (svr4) || defined (svr3)
  14497. X    sighold (SIGINT);
  14498. X    sighold (SIGTERM);
  14499. X#endif
  14500. X  sprintf (sstdout, "%s.%d", STDOUT, getpid());
  14501. X  sprintf (sstderr, "%s.%d", STDERR, getpid());
  14502. X  syscom ("%s > %s 2> %s", prog, sstdout, sstderr);
  14503. X#ifdef bsd
  14504. X    sigsetmask (sig_mask);
  14505. X#elif defined (svr4) || defined (svr3)
  14506. X    sigrelse (SIGINT);
  14507. X    sigrelse (SIGTERM);
  14508. X#endif
  14509. X  create_header (&f, mailforwardf, sys.server.address, sender, request, FALSE,
  14510. X         OK, FALSE, FALSE);
  14511. X  if (!stat (sstdout, &stat_buf) && stat_buf.st_size > 0) {
  14512. X    fprintf (f, "Output from stdout:\n");
  14513. X    fclose (f);
  14514. X    cat_append (sstdout, mailforwardf);
  14515. X    APPEND_TELNET ("execute");
  14516. X    DELIVER_MAIL (sender, FALSE);
  14517. X  }
  14518. X  if (!stat (sstderr, &stat_buf) && stat_buf.st_size > 0) {
  14519. X    if (interactive)
  14520. X      if (stat (sstdout, &stat_buf))
  14521. X    create_header (&f, mailforwardf, sys.server.address, sender, request,
  14522. X               FALSE, OK, FALSE, FALSE);
  14523. X      else
  14524. X    f = fopen (mailforwardf, "a");
  14525. X    else
  14526. X      create_header (&f, mailforwardf, sys.server.address, sender, request,
  14527. X             FALSE, OK, FALSE, FALSE);
  14528. X    fprintf (f, "Output from stderr:\n");
  14529. X    fclose (f);
  14530. X    cat_append (sstderr, mailforwardf);
  14531. X    APPEND_TELNET ("execute");
  14532. X    DELIVER_MAIL (sender, FALSE);
  14533. X  }
  14534. X  unlink (sstdout);
  14535. X  unlink (sstderr);
  14536. X}
  14537. X
  14538. X/*
  14539. X  Initialize the commands[].
  14540. X*/
  14541. X
  14542. Xvoid init_commands ()
  14543. X{
  14544. X  COMMAND (0, "HELP", 0x1, help);
  14545. X  COMMAND (1, "SET", 0x2, set);
  14546. X  COMMAND (2, "SUBSCRIBE", 0x4, subscribe);
  14547. X  COMMAND (3, "UNSUBSCRIBE", 0x8, unsubscribe);
  14548. X  COMMAND (4, "SIGNOFF", 0x8, unsubscribe);
  14549. X  COMMAND (5, "RECIPIENTS", 0x10, recipients);
  14550. X  COMMAND (6, "REVIEW", 0x10, recipients);
  14551. X  COMMAND (7, "INFORMATION", 0x20, info);
  14552. X  COMMAND (8, "STATISTICS", 0x40, stats);
  14553. X  COMMAND (9, "SHUTDOWN", 0x80, Shutdown);
  14554. X  COMMAND (10, "RESTART", 0x100, restart);
  14555. X  COMMAND (11, "LISTS", 0x200, lists);
  14556. X  COMMAND (12, "INDEX", 0x400, Index);
  14557. X  COMMAND (13, "GET", 0x800, get);
  14558. X  COMMAND (14, "RELEASE", 0x1000, release);
  14559. X  COMMAND (15, "WHICH", 0x2000, which);
  14560. X  COMMAND (16, "SYSTEM", 0x4000, System);
  14561. X  COMMAND (17, "REPORTS", 0x8000, get_sys_files);
  14562. X  COMMAND (18, "EDIT", 0x10000, get_sys_files);
  14563. X  COMMAND (19, "PUT", 0x20000, put);
  14564. X  COMMAND (20, "NOTIFY", 0x40000, notify);
  14565. X  COMMAND (21, "APPROVE", 0x80000, approve);
  14566. X  COMMAND (22, "DISCARD", 0x100000, discard);
  14567. X  COMMAND (23, "EXECUTE", 0x200000, execute);
  14568. X  COMMAND (24, "RUN", 0x400000, unix_cmd);
  14569. X  COMMAND (25, "FAX", 0x800000, get);
  14570. X  COMMAND (26, "SEARCH", 0x1000000, search);
  14571. X  COMMAND (27, "VIEW", 0x800, get);
  14572. X}
  14573. X
  14574. Xvoid usage ()
  14575. X{
  14576. X  fprintf (stderr, "Usage: listproc [-1] [-e] [-i] [-n] [-a <LIST_ALIAS>] \
  14577. X[-c <LIST_ALIAS>] {[-r <request>]}* {[-d <request>]}* {[-b <request>]}* [-B] \
  14578. X[-D]\n\
  14579. X-1: Execute only once.\n\
  14580. X-e: Echo reports to the screen.\n\
  14581. X-i: Interactive mode (do not send mail).\n\
  14582. X-n: Do not notify peer servers.\n\
  14583. X-a: Turn off automatic subscription for the specified list.\n\
  14584. X-c: Conceal the specified list from LISTS requests.\n\
  14585. X-r: Set restriction on 'request'.\n\
  14586. X-d: Disable 'request'.\n\
  14587. X-b: Batch 'request'.\n\
  14588. X-B: Process the batch queue.\n\
  14589. X-D: Turn debug on.\n");
  14590. X  exit (3);
  14591. X}
  14592. X
  14593. Xvoid server_config (char *alias)
  14594. X{
  14595. X  setup_string (list_mail_f, alias, LIST_MAIL_FILE);
  14596. X  setup_string (list_moderated_f, alias, LIST_MODERATED_F);
  14597. X  setup_string (infof, alias, INFO_FILE);
  14598. X  setup_string (recipf, alias, RECIP_FILE);
  14599. X  setup_string (welcomef, alias, WELCOME_FILE);
  14600. X  setup_string (subscribersf, alias, SUBSCRIBERS);
  14601. X  setup_string (aliasesf, alias, ALIASES);
  14602. X  setup_string (newsf, alias, NEWSF);
  14603. X  setup_string (peersf, alias, PEERS);
  14604. X  setup_string (headersf, alias, HEADERS);
  14605. X  setup_string (ignoredf, alias, IGNORED);
  14606. X  setup_string (aliases_timestampf, alias, ALIASES_TIMESTAMPF);
  14607. X  setup_string (ignored_timestampf, alias, IGNORED_TIMESTAMPF);
  14608. X  setup_string (info_timestampf, alias, INFO_TIMESTAMPF);
  14609. X  setup_string (subscribers_timestampf, alias, SUBSCRIBERS_TIMESTAMPF);
  14610. X  setup_string (welcome_timestampf, alias, WELCOME_TIMESTAMPF);
  14611. X  setup_string (news_timestampf, alias, NEWS_TIMESTAMPF);
  14612. X  setup_string (peers_timestampf, alias, PEERS_TIMESTAMPF);
  14613. X}
  14614. X
  14615. X/*
  14616. X  Graceful exit. Remove pid file.
  14617. X*/
  14618. X
  14619. Xint gexit (int exitcode)
  14620. X{
  14621. X  unlink (tsprintf ("%s.%d", PID_SERVER, getpid()));
  14622. X  exit (exitcode);
  14623. X}
  14624. *-*-END-of-src/listproc.c-*-*
  14625. echo x - src/misc.c
  14626. sed 's/^X//' >src/misc.c <<'*-*-END-of-src/misc.c-*-*'
  14627. X/*
  14628. X  ----------------------------------------------------------------------------
  14629. X  |                      GENERAL PURPOSE FUNCTIONS                           |
  14630. X  |                                                                          |
  14631. X  |                             Version 3.0                                  |
  14632. X  |                                                                          |
  14633. X  |                (or, when Computer Science gets to you)                   |
  14634. X  |                                                                          |
  14635. X  |                    Written by Anastasios Kotsikonas                      |
  14636. X  |                           (tasos@cs.bu.edu)                              |
  14637. X  |                                                                          |
  14638. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  14639. X  | whole and not in parts, as long as you do not remove or alter the author |
  14640. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  14641. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  14642. X  | provided for your personal use, you may not alter the functions          |
  14643. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  14644. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  14645. X  | any changes you may have made. No part of the source code bearing a         |
  14646. X  | copyright notice can be included in commercial software systems without  |
  14647. X  | written permission by the author.                         |
  14648. X  | By using this software you are bound by this agreement.                  |
  14649. X  | This software comes with no warranties and cannot be sold for profit.    |
  14650. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  14651. X  | files when distributing this software.                                   |
  14652. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  14653. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  14654. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  14655. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  14656. X  | (ii).                                                                    |
  14657. X  ----------------------------------------------------------------------------
  14658. X*/
  14659. X
  14660. X#include <stdio.h>
  14661. X#include <sys/types.h>
  14662. X#ifdef SYSLOG
  14663. X# ifdef ultrix
  14664. X#  include <sys/syslog.h>
  14665. X# else
  14666. X#  include <syslog.h>
  14667. X# endif
  14668. X#endif
  14669. X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
  14670. X  && !defined (sequent) && !defined (unknown_port)
  14671. X# include <malloc.h>
  14672. X#endif
  14673. X#include <time.h>
  14674. X#include <string.h>
  14675. X#include <signal.h>
  14676. X#include <ctype.h>
  14677. X#ifndef unknown_port
  14678. X# ifndef __NeXT__
  14679. X#  include <unistd.h>
  14680. X# else
  14681. X#  include <libc.h>
  14682. X# endif
  14683. X#endif
  14684. X#include <sys/stat.h>
  14685. X#include <fcntl.h>
  14686. X#include <errno.h>
  14687. X#ifdef unknown_port
  14688. Xextern int errno;
  14689. X#endif
  14690. X#include <signal.h>
  14691. X#include <math.h>
  14692. X#include "defs.h"
  14693. X#include "struct.h"
  14694. X#ifdef GO_INTERACTIVE
  14695. X# include <sys/socket.h>
  14696. X#endif
  14697. X
  14698. X#define  MYWEXITSTATUS(stat)    ((int)(((stat)>>8)&0377))
  14699. X
  14700. Xextern  COMMANDS commands[MAX_COMMANDS];
  14701. Xextern  REMOTE *rlists, *matched_rlists;
  14702. Xextern  BOOLEAN extract_sender (char *);
  14703. Xextern  char *options [MAX_SET_OPTIONS];
  14704. Xextern  char *values [MAX_SET_OPTIONS];
  14705. X
  14706. X#if !defined (__NeXT__) && !defined (__osf__) && !defined (_AIX)
  14707. Xextern long int atoi (char *);
  14708. X#else
  14709. Xextern int atoi (const char *);
  14710. X#endif
  14711. Xextern BOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *,
  14712. X               BOOLEAN);
  14713. Xextern void process_message (char *, char *, BOOLEAN, BOOLEAN);
  14714. Xextern int re_strcmp (char *, char *, char *);
  14715. Xextern int mv (char *, char *);
  14716. X
  14717. X#ifdef __STDC__
  14718. X# include "ansi/misc.h"
  14719. X# include <stdarg.h>
  14720. Xint     syscom (char *, ...);
  14721. Xextern  char *tsprintf (char *, ...);
  14722. X#else
  14723. X# include "nonansi/misc.h"
  14724. X# include <varargs.h>
  14725. Xint     syscom ();
  14726. Xextern  char *tsprintf ();
  14727. X#endif
  14728. Xint    sys_config (FILE *, SYS *);
  14729. Xvoid    config_owner_prefs (SYS *, int, FILE *);
  14730. Xchar    *locase (char *);
  14731. Xchar    *upcase (char *);
  14732. Xvoid    shadow_password (char *);
  14733. Xvoid    report_progress (FILE *, char *, int);
  14734. Xvoid    distribute (FILE *, void (*)(char *, char *, BOOLEAN, BOOLEAN), FILE *,
  14735. X            char *, char *, char *, char *, BOOLEAN);
  14736. XBOOLEAN strinstr (char *, char *);
  14737. Xchar    *extract_filename (char *);
  14738. Xint     _getopt (int, char **, char *);
  14739. Xchar    *clean_name (char *);
  14740. Xvoid    clean_request (char *);
  14741. Xvoid    get_list_name (char *, char *);
  14742. Xvoid    free_remote_matched (REMOTE **);
  14743. Xint    get_list_id (char *, SYS *, int);
  14744. XREMOTE  *check_remote (REMOTE *, char *);
  14745. Xvoid    setup_string (char *, char *, char *);
  14746. Xchar    *_strstr (char *, char *);
  14747. Xvoid    shrink (char *);
  14748. XBOOLEAN requested_part (char *, int);
  14749. Xvoid    free_remote (REMOTE **);
  14750. Xint    my_system (char *);
  14751. XBOOLEAN remove_msg (char *, int, FILE *);
  14752. Xvoid    read_params (char *, char *, char *, FILE *, FILE *);
  14753. Xint    lock_file (char *, int, int, BOOLEAN);
  14754. Xvoid    unlock_file (int);
  14755. Xlong int write_to_fd (int, char *, long int);
  14756. XBOOLEAN mkdir1 (char *, char *, char *);
  14757. Xint    otoi (char *);
  14758. XBOOLEAN get_field (char **, char, char *);
  14759. XBOOLEAN make_indexes (char *, char *, char *, char *, char *);
  14760. Xint    insert_word (char *, char **, int, int, int);
  14761. Xchar    *skip_to_word (char *, int);
  14762. Xchar    *mystrdup (char *);
  14763. X
  14764. X/*
  14765. X  Execute a system request.
  14766. X*/
  14767. X
  14768. X#ifdef __STDC__
  14769. Xint syscom (char *control, ...)
  14770. X#else
  14771. Xint syscom (control, va_alist)
  14772. Xchar *control;
  14773. Xva_dcl
  14774. X#endif
  14775. X{
  14776. X  char command [10240], *ambersand;
  14777. X  int mask;
  14778. X  extern SYS sys;
  14779. X  extern BOOLEAN tty_echo;
  14780. X  va_list ap;
  14781. X  int status;
  14782. X  FILE *f;
  14783. X#ifdef ultrix
  14784. X  time_t time_is = 0;
  14785. X#else
  14786. X  long int time_is = 0;
  14787. X#endif
  14788. X  struct tm *t;
  14789. X
  14790. X#ifdef __STDC__
  14791. X  va_start (ap, control);
  14792. X#else
  14793. X  va_start (ap);
  14794. X#endif
  14795. X  RESET (command);
  14796. X  vsprintf (command, control, ap);
  14797. X  va_end (ap);
  14798. X  if (!_strstr (command, " 2>")) {
  14799. X    sprintf (command + strlen (command), " 2>> %s", WARNING);
  14800. X    if ((ambersand = _strstr (command, " &")))
  14801. X      *(ambersand + 1) = ' ',
  14802. X      strcat (command, " &");
  14803. X  }
  14804. X#ifdef GO_INTERACTIVE
  14805. X# if defined (bsd)
  14806. X#  ifdef SIGCLD
  14807. X      mask = sigblock (sigmask (SIGCLD));
  14808. X#  elif defined (SIGCHLD)
  14809. X      mask = sigblock (sigmask (SIGCHLD));
  14810. X#  endif
  14811. X# elif (defined (svr4) || defined (svr3)) && !defined (stellar) && \
  14812. X  !defined (M_UNIX) && !defined (M_XENIX) && !defined (sco) && \
  14813. X  !defined (unknown_port)
  14814. X#  ifdef SIGCLD
  14815. X      sighold (SIGCLD);
  14816. X#  elif defined (SIGCHLD)
  14817. X      sighold (SIGCHLD);
  14818. X#  endif
  14819. X# endif
  14820. X#endif
  14821. X  if ((sys.options & USE_MY_SYSTEM) == 0)
  14822. X    status = system (command);
  14823. X  else
  14824. X    status = my_system (command);
  14825. X#ifdef GO_INTERACTIVE
  14826. X# if defined (bsd) && (defined (SIGCLD) || defined (SIGCHLD))
  14827. X    sigsetmask (mask);
  14828. X# elif (defined (svr3) || defined (svr4)) && !defined (stellar) && \
  14829. X  !defined (M_UNIX) && !defined (M_XENIX) && !defined (sco) && \
  14830. X  !defined (unknown_port)
  14831. X#  ifdef SIGCLD
  14832. X    sigrelse (SIGCLD);
  14833. X#   elif defined (SIGCHLD)
  14834. X    sigrelse (SIGCHLD);
  14835. X#   endif
  14836. X# endif
  14837. X#endif
  14838. X  if (status > 0) {
  14839. X    if ((f = fopen (WARNING, "a")) != NULL)
  14840. X      fprintf (f, "\nWARNING: System call exit status %d: %s\n",
  14841. X           MYWEXITSTATUS (status), command),
  14842. X      time (&time_is),
  14843. X      t = localtime (&time_is),
  14844. X      fprintf (f, "Time/Date: %2d:%.2d:%.2d, %2d/%.2d/%2d\n",
  14845. X               t->tm_hour, t->tm_min, t->tm_sec, t->tm_mon + 1, t->tm_mday,
  14846. X               t->tm_year),
  14847. X      fclose (f);
  14848. X    if (tty_echo)
  14849. X      printf ("\nWARNING: System call exit status %d: %s\n",
  14850. X          MYWEXITSTATUS (status), command);
  14851. X  }
  14852. X  return status;
  14853. X}
  14854. X
  14855. X/*
  14856. X  Initialize the 'sys' structure from the CONFIG file. It returns the number
  14857. X  of lists in the system.
  14858. X*/
  14859. X
  14860. Xint sys_config (FILE *report, SYS *sys)
  14861. X{
  14862. X  FILE *config;
  14863. X  char cmd [MAX_LINE];
  14864. X  char args [MAX_LINE];
  14865. X  char arg [MAX_LINE];
  14866. X  char line [MAX_LINE];
  14867. X  char *comment, *cmdarg, *start, *end;
  14868. X  int nlists = 0, i, j, k, id;
  14869. X  BOOLEAN notok, found;
  14870. X  REMOTE *remote;
  14871. X  PRECIOUS_HEADER *header;
  14872. X  _CMDS *unix_cmd;
  14873. X
  14874. X  for (i = 0; i < MAX_LISTS; i++)
  14875. X    sys->lists[i].digest_lines = 1000,
  14876. X    sys->lists[i].digest_hours = 24,
  14877. X    sys->lists[i].disabled_commands = 0,
  14878. X    sys->lists[i].owner_prefs = 0,
  14879. X    sys->lists[i].header = NULL,
  14880. X    sys->lists[i].unix_cmds = NULL,
  14881. X    sys->lists[i].options = 0,
  14882. X    sys->lists[i].max_messages = 0,
  14883. X    RESET (sys->lists[i].alias),
  14884. X    RESET (sys->lists[i].address),
  14885. X    RESET (sys->lists[i].password),
  14886. X    RESET (sys->lists[i].owner),
  14887. X    RESET (sys->lists[i].comment),
  14888. X    RESET (sys->lists[i].cmdoptions),
  14889. X    RESET (sys->lists[i].arch_dir),
  14890. X    RESET (sys->lists[i].farch_dir),
  14891. X    RESET (sys->lists[i].arch_pass),
  14892. X    RESET (sys->lists[i].arch_spec);
  14893. X  RESET (sys->server.address), RESET (sys->server.cmdoptions),
  14894. X  RESET (sys->server.comment), RESET (sys->serverd_cmdoptions),
  14895. X  RESET (sys->server.password), RESET (sys->arg), RESET (sys->manager),
  14896. X  RESET (sys->organization), RESET (sys->fax.prog);
  14897. X  sys->limits.msg = sys->limits.files = 100000;
  14898. X  sys->server.manager_prefs = 0;
  14899. X  strcpy (sys->server.address, DEFAULT_SERVER_ADDRESS);
  14900. X  strcpy (sys->server.cmdoptions, DEFAULT_SERVER_CMDOPTIONS);
  14901. X  strcpy (sys->server.comment, DEFAULT_SERVER_COMMENT);
  14902. X  strcpy (sys->manager, DEFAULT_MANAGER);
  14903. X  sys->mail.method = BINMAIL;
  14904. X  strcpy (sys->mail.precedence, DEFAULT_PRECEDENCE);
  14905. X  sys->options = 0;
  14906. X  sys->users = 100;
  14907. X  sys->frequency = 5;
  14908. X  sys->batch.start = 8; /* 8 am */
  14909. X  sys->batch.stop = 20; /* 8 pm */
  14910. X  OPEN_FILE (config, CONFIG, "r", "sys_config");
  14911. X  chmod (CONFIG, 384);
  14912. X  while (! feof (config)) {
  14913. X    line [0] = args [0] = RESET (cmd);
  14914. X    fgets (line, MAX_LINE - 2, config);
  14915. X    sscanf (line, "%s", cmd);
  14916. X    if (cmd[0] == EOS)
  14917. X      continue;
  14918. X/*    fgets (args, MAX_LINE - 2, config);*/
  14919. X    read_params (line, args, cmd, config, NULL);
  14920. X    if (args [strlen (args) - 1] == '\n')
  14921. X      args [strlen (args) - 1] = EOS;
  14922. X    if (cmd[0] == '#')
  14923. X      continue;
  14924. X    if (!strcmp (locase (cmd), "list")) {
  14925. X      if (nlists >= MAX_LISTS) {
  14926. X    report_progress (report,
  14927. X             tsprintf ("\nsys_config(): List %s ignored: too many \
  14928. Xlists\n",
  14929. X                   args), FALSE);
  14930. X    continue;
  14931. X      }
  14932. X      comment = strchr (args, '#');
  14933. X      if (comment)
  14934. X    *comment = EOS;
  14935. X      sscanf (args, "%s %s %s %s", sys->lists [nlists].alias,
  14936. X          sys->lists [nlists].address, sys->lists [nlists].owner,
  14937. X          sys->lists [nlists].password);
  14938. X      if (get_list_id (sys->lists [nlists].alias, sys, nlists) >= 0 &&
  14939. X      nlists > 0)
  14940. X    report_progress (report,
  14941. X             tsprintf ("\nsys_config(): Duplicate list %s in %s",
  14942. X                   sys->lists [nlists].alias, CONFIG), TRUE),
  14943. X    exit (4);
  14944. X      cmdarg = _strstr (args, " -");
  14945. X      if (!cmdarg)
  14946. X    cmdarg = _strstr (args, "\t-");
  14947. X      if (cmdarg)
  14948. X    strcat (sys->lists [nlists].cmdoptions, cmdarg);
  14949. X      upcase (sys->lists [nlists].alias);
  14950. X      locase (sys->lists [nlists].address);
  14951. X      locase (sys->lists [nlists].owner);
  14952. X      upcase (sys->lists [nlists].password);
  14953. X      ++nlists;
  14954. X    }
  14955. X    else if (!strcmp (cmd, "server")) {
  14956. X      comment = strchr (args, '#');
  14957. X      if (comment)
  14958. X        *comment = EOS;
  14959. X      sscanf (args, "%s", sys->server.address);
  14960. X      cmdarg = _strstr (args, " -");
  14961. X      if (!cmdarg)
  14962. X    cmdarg = _strstr (args, "\t-");
  14963. X      if (cmdarg)
  14964. X    strcat (sys->server.cmdoptions, cmdarg);
  14965. X      locase (sys->server.address);
  14966. X    }
  14967. X    else if (!strcmp (cmd, "remote")) {
  14968. X      if ((remote = (REMOTE *) malloc (sizeof (*remote))) == NULL)
  14969. X    report_progress (report,
  14970. X             tsprintf ("\nsys_config(): malloc() failed during \
  14971. X'remote' in %s",
  14972. X                   CONFIG), TRUE),
  14973. X    exit (11);
  14974. X      RESET (remote->inet_addr);
  14975. X      remote->port = 0;
  14976. X      sscanf (args, "%s %s %s %s %d", remote->alias, remote->address,
  14977. X          remote->listproc, remote->inet_addr, &remote->port);
  14978. X      upcase (remote->alias);
  14979. X      locase (remote->address);
  14980. X      locase (remote->listproc);
  14981. X      if (remote->inet_addr[0] == '#')
  14982. X    RESET (remote->inet_addr);
  14983. X      else if (remote->port == 0)
  14984. X    remote->port = DEFAULT_ILP_PORT;
  14985. X      comment = strchr (args, '#');
  14986. X      if (!comment)
  14987. X        report_progress (report,
  14988. X             tsprintf ("\nsys_config(): Missing # for 'remote' in %s",
  14989. X                   CONFIG), TRUE),
  14990. X        exit (4);
  14991. X      RESET (remote->comment);
  14992. X      strcat (remote->comment, comment + 1);
  14993. X      remote->next = rlists;  /* Link it to the existing list */
  14994. X      rlists = remote;
  14995. X    }
  14996. X    else if (!strcmp (cmd, "frequency")) {
  14997. X      sscanf (args, "%d", &sys->frequency);
  14998. X      if (sys->frequency < 0 || sys->frequency > 86400)
  14999. X    report_progress (report,
  15000. X             tsprintf ("\nsys_config(): Invalid 'frequency' \
  15001. Xargument %d in %s",
  15002. X                   sys->frequency, CONFIG), TRUE),
  15003. X    exit (4);
  15004. X    }
  15005. X    else if (!strcmp (cmd, "limit")) {
  15006. X      sscanf (args, "%s", sys->arg);
  15007. X      if (!strcmp (locase (sys->arg), "message"))
  15008. X    sys->options |= LIMIT_MSG,
  15009. X        sscanf (args, "%s %ld", sys->arg, &sys->limits.msg);
  15010. X      else if (!strcmp (sys->arg, "files"))
  15011. X    sys->options |= LIMIT_FILES,
  15012. X    sscanf (args, "%s %ld", sys->arg, &sys->limits.files);
  15013. X      else
  15014. X     report_progress (report,
  15015. X             tsprintf ("\nsys_config(): Invalid argument %s to \
  15016. X'limit' in %s",
  15017. X                   sys->arg, CONFIG), TRUE),
  15018. X    exit (4);
  15019. X    }
  15020. X    else if (!strcmp (cmd, "ceiling")) {
  15021. X      sscanf (args, "%s ", sys->arg);
  15022. X      upcase (sys->arg);
  15023. X      id = get_list_id (sys->arg, sys, nlists);
  15024. X      if (id < 0)
  15025. X        report_progress (report,
  15026. X             tsprintf ("\nsys_config(): Unrecognized list name %s \
  15027. Xfor 'ceiling' in %s", sys->arg, CONFIG), TRUE),
  15028. X        exit (4);
  15029. X      sscanf (args, "%s %d", sys->arg, &sys->lists[id].max_messages);
  15030. X    }
  15031. X    else if (!strcmp (cmd, "batch")) {
  15032. X      sscanf (args, "%u %u", &sys->batch.start, &sys->batch.stop);
  15033. X      sys->batch.start %= 24;
  15034. X      sys->batch.stop %= 24;
  15035. X      if (sys->batch.stop == 0)
  15036. X    sys->batch.stop = 24;
  15037. X      if (sys->batch.start >= sys->batch.stop ||
  15038. X      (sys->batch.start == 0 && sys->batch.stop == 24))
  15039. X    report_progress (report, tsprintf ("\nsys_config(): Invalid times to \
  15040. X'batch' in %s",
  15041. X                       CONFIG), TRUE),
  15042. X    exit (4);
  15043. X    }
  15044. X    else if (!strcmp (cmd, "option")) {
  15045. X      sscanf (args, "%s", sys->arg);
  15046. X      if (!strcmp (locase (sys->arg), "bsd_ps"))
  15047. X    sys->options |= BSD_PS;
  15048. X      else if (!strcmp (sys->arg, "sysv_ps"))
  15049. X    sys->options |= SYSV_PS;
  15050. X      else if (!strcmp (sys->arg, "bsd_mail"))
  15051. X    sys->options |= BSD_MAIL;
  15052. X      else if (!strcmp (sys->arg, "bad_telnet"))
  15053. X    sys->options |= USE_MY_SYSTEM;
  15054. X      else if (!strcmp (sys->arg, "post_mail"))
  15055. X    sys->options |= POST_MAIL;
  15056. X      else if (!strcmp (sys->arg, "gate_mail"))
  15057. X    sys->options |= GATE_MAIL;
  15058. X      else if (!strcmp (sys->arg, "ignore_invalid_requests"))
  15059. X    sys->options |= IGNR_INVLD_RQSTS;
  15060. X      else if (!strcmp (sys->arg, "relaxed_syntax"))
  15061. X    sys->options |= RELAXED_SYNTAX;
  15062. X      else
  15063. X    report_progress (report, tsprintf ("\nsys_config(): Invalid argument \
  15064. X%s to 'option' in %s",
  15065. X                       sys->arg, CONFIG), TRUE),
  15066. X    exit (4);
  15067. X    }
  15068. X    else if (!strcmp (cmd, "serverd")) {
  15069. X      comment = strchr (args, '#');
  15070. X      if (comment)
  15071. X        *comment = EOS;
  15072. X      cmdarg = strchr (args, '-');
  15073. X      if (cmdarg)
  15074. X    strcat (sys->serverd_cmdoptions, cmdarg);
  15075. X    }
  15076. X    else if (!strcmp (cmd, "organization")) {
  15077. X      comment = strchr (args, '#');
  15078. X      if (comment)
  15079. X        *comment = EOS;
  15080. X      strcpy (sys->organization, args + 1);
  15081. X    }
  15082. X    else if (!strcmp (cmd, "restriction"))
  15083. X      sscanf (args, "%d", &sys->users);
  15084. X    else if (!strcmp (cmd, "manager"))
  15085. X      sscanf (args, "%s", sys->manager);
  15086. X    else if (!strcmp (cmd, "password"))
  15087. X      sscanf (args, "%s", sys->server.password),
  15088. X      upcase (sys->server.password);
  15089. X    else if (!strcmp (cmd, "disable")) {
  15090. X      if (commands[0].name == NULL)  /* Array not initialized */
  15091. X    continue;
  15092. X      sscanf (args, "%s", sys->arg);
  15093. X      upcase (sys->arg);
  15094. X      id = get_list_id (sys->arg, sys, nlists);
  15095. X      if (id < 0)
  15096. X      report_progress (report, tsprintf ("\nsys_config(): Unrecognized \
  15097. Xlist name %s for 'disable' in %s", sys->arg, CONFIG), TRUE),
  15098. X      exit (4);
  15099. X      sscanf (args, "%s %s", sys->arg, sys->arg); /* Get request to disable */
  15100. X      upcase (sys->arg);
  15101. X      notok = FALSE;
  15102. X      k = 0;
  15103. X      for (i = 0; i < MAX_COMMANDS; ++i) {
  15104. X    notok &= (((j = strncmp (sys->arg, commands[i].name, strlen (sys->arg)))
  15105. X           != 0) ? 1 : 0);
  15106. X    if (!j)
  15107. X      ++k,
  15108. X      sys->lists[id].disabled_commands |= commands[i].mask;
  15109. X      }
  15110. X      if (notok)
  15111. X    report_progress (report,
  15112. X             tsprintf ("\nsys_config(): Unrecognized \
  15113. Xrequest %s to 'disable' for list %s in %s",
  15114. X                   sys->arg, sys->lists[id].alias, CONFIG),
  15115. X             TRUE),
  15116. X    exit (4);
  15117. X      if (k > 1)
  15118. X    report_progress (report, tsprintf ("\nsys_config(): Ambiguous request \
  15119. X%s to 'disable' for list %s in %s", sys->arg, sys->lists[id].alias, CONFIG),
  15120. X             TRUE),
  15121. X    exit (4);
  15122. X    }
  15123. X    else if (!strcmp (cmd, "comment")) {
  15124. X      sscanf (args, "%s", sys->arg);
  15125. X      if (!strcmp (locase (sys->arg), "server")) {
  15126. X    comment = strchr (args, '#');
  15127. X    if (!comment)
  15128. X          report_progress (report, tsprintf ("\nsys_config(): Missing # for \
  15129. X'comment' in %s",
  15130. X                         CONFIG), TRUE),
  15131. X          exit (4);
  15132. X    RESET (sys->server.comment);
  15133. X    strcat (sys->server.comment, comment + 1);
  15134. X      }
  15135. X      else {  /* Some list name was specified */
  15136. X    upcase (sys->arg);
  15137. X    id = get_list_id (sys->arg, sys, nlists);
  15138. X    if (id < 0)
  15139. X      report_progress (report, tsprintf ("\nsys_config(): Unrecognized \
  15140. Xlist name %s for 'comment' in %s", sys->arg, CONFIG), TRUE),
  15141. X      exit (4);
  15142. X    comment = strchr (args, '#');
  15143. X    if (!comment)
  15144. X      report_progress (report, tsprintf ("\nsys_config(): Missing # for \
  15145. Xcomment in %s", CONFIG), TRUE),
  15146. X      exit (4);
  15147. X    RESET (sys->lists[id].comment);
  15148. X    strcat (sys->lists[id].comment, comment + 1);
  15149. X      }
  15150. X    }
  15151. X    else if (!strcmp (cmd, "mailmethod")) {
  15152. X      sscanf (args, "%s", sys->arg);
  15153. X      if (!strcmp (locase (sys->arg), "telnet"))
  15154. X    sys->mail.method = TELNET,
  15155. X     sys->options |= USE_TELNET;
  15156. X      else if (!strcmp (locase (sys->arg), "system")) {
  15157. X#ifndef TCP_IP
  15158. X    report_progress (report, "\nsys_config(): No system support for \
  15159. X'system' mailmethod. Select another method.", TRUE);
  15160. X    exit (1);
  15161. X#endif
  15162. X    sys->options |= (USE_TELNET | USE_SYSMAIL);
  15163. X      }
  15164. X      else if (!strcmp (sys->arg, "sendmail") || !strcmp (sys->arg, "rmail")) {
  15165. X    if (!(sys->mail.method = (char *) malloc (256 * sizeof (char))))
  15166. X      report_progress (report, tsprintf ("\nsys_config(): malloc() failed \
  15167. Xduring 'mailmethod' in %s", CONFIG), TRUE),
  15168. X      exit (11);
  15169. X    sscanf (args, "%s %s", sys->arg, sys->mail.method);
  15170. X    locase (sys->mail.method);
  15171. X    strcat (sys->mail.method, " > /dev/null 2>&1");
  15172. X      }
  15173. X      else if (!strcmp (sys->arg, "binmail"))
  15174. X    sys->mail.method = BINMAIL;
  15175. X      else if (!strcmp (sys->arg, "env_var"))
  15176. X    sys->options |= USE_ENV_VAR,
  15177. X    sscanf (args, "%s %s %s", sys->arg, sys->mail.env_var,
  15178. X            sys->mail.mail_prog),
  15179. X    locase (sys->mail.mail_prog),
  15180. X    upcase (sys->mail.env_var);
  15181. X      else
  15182. X    report_progress (report, tsprintf ("\nsys_config(): Unrecognized mail \
  15183. Xmethod %s in %s",
  15184. X                       sys->arg, CONFIG), TRUE),
  15185. X    exit (4);
  15186. X    }
  15187. X    else if (!strcmp (cmd, "digest")) { /* "digest list lines hours" */
  15188. X      sscanf (args, "%s ", sys->arg);
  15189. X      upcase (sys->arg);
  15190. X      id = get_list_id (sys->arg, sys, nlists);
  15191. X      if (id < 0)
  15192. X        report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
  15193. Xname %s for 'digest' in %s", sys->arg, CONFIG), TRUE),
  15194. X        exit (4);
  15195. X      sscanf (args, "%s %d %d", sys->arg, &sys->lists[id].digest_lines,
  15196. X          &sys->lists[id].digest_hours);
  15197. X    }
  15198. X    else if (!strcmp (cmd, "header")) { /* Precious header lines to be saved */
  15199. X      sscanf (args, "%s ", sys->arg);
  15200. X      upcase (sys->arg);
  15201. X      id = get_list_id (sys->arg, sys, nlists);
  15202. X      if (id < 0)
  15203. X        report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
  15204. Xname %s for 'header' in %s", sys->arg, CONFIG), TRUE),
  15205. X        exit (4);
  15206. X      if (!(comment = strchr (args, '{')))
  15207. X    report_progress (report, tsprintf ("\nsys_config(): Missing '{' for \
  15208. X'header' in %s",
  15209. X                       CONFIG), TRUE),
  15210. X        exit (4);
  15211. X      RESET (sys->arg);
  15212. X      sys->lists[id].header = NULL;
  15213. X      while (!feof (config) && strcmp (sys->arg, "}")) {
  15214. X    RESET (sys->arg);
  15215. X    fscanf (config, "%s\n", sys->arg);
  15216. X    if (sys->arg[0] == '#') {
  15217. X      fgets (sys->arg, MAX_LINE - 2, config);
  15218. X      continue;
  15219. X    }
  15220. X    if (sys->arg[0] != EOS && strcmp (sys->arg, "}")) {
  15221. X      if (! (header =
  15222. X         (PRECIOUS_HEADER *) malloc (sizeof (PRECIOUS_HEADER))))
  15223. X        report_progress (report, tsprintf ("\nsys_config(): malloc() \
  15224. Xfailed during 'header' in %s", CONFIG), TRUE),
  15225. X        exit (11);
  15226. X      if (! (header->line =
  15227. X          (char *) malloc ((strlen (sys->arg) + 1) * sizeof (char))))
  15228. X        report_progress (report, tsprintf ("\nsys_config(): malloc() \
  15229. Xfailed during 'header' in %s", CONFIG), TRUE),
  15230. X        exit (11);
  15231. X      strcpy (header->line, sys->arg);
  15232. X      header->next = sys->lists[id].header;
  15233. X      sys->lists[id].header = header;
  15234. X    }
  15235. X      }
  15236. X      if (feof (config) && strcmp (sys->arg, "}"))
  15237. X    report_progress (report, tsprintf ("\nsys_config(): Missing '}' for \
  15238. X'header' for list %s in %s", sys->lists[id].alias, CONFIG), TRUE),
  15239. X    exit (4);
  15240. X    }
  15241. X    else if (!strcmp (cmd, "default")) { /* Default list values */
  15242. X      sscanf (args, "%s ", sys->arg);
  15243. X      upcase (sys->arg);
  15244. X      id = get_list_id (sys->arg, sys, nlists);
  15245. X      if (id < 0)
  15246. X    report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
  15247. Xname %s for 'default' in %s", sys->arg, CONFIG), TRUE),
  15248. X    exit (4);
  15249. X      if (!(comment = strchr (args, '{')))
  15250. X    report_progress (report, tsprintf ("\nsys_config(): Missing '{' for \
  15251. X'default' in %s",
  15252. X                       CONFIG), TRUE),
  15253. X    exit (4);
  15254. X      RESET (sys->arg);
  15255. X      while (!feof (config) && strcmp (sys->arg, "}")) {
  15256. X    RESET (sys->arg);
  15257. X    fscanf (config, "%s ", sys->arg);
  15258. X    upcase (sys->arg);
  15259. X    if (sys->arg[0] == '#') {
  15260. X      fgets (sys->arg, MAX_LINE - 2, config);
  15261. X      continue;
  15262. X    }
  15263. X    if (sys->arg[0] != EOS && strcmp (sys->arg, "}")) {
  15264. X      found = FALSE;
  15265. X      for (i = 0; i < MAX_SET_OPTIONS; i++)
  15266. X        if (!strcmp (sys->arg, options[i])) {
  15267. X          found = TRUE;
  15268. X          break;
  15269. X        }
  15270. X      if (!found)
  15271. X        report_progress (report, tsprintf ("\nsys_config(): Default value \
  15272. X%s not recognized in %s", sys->arg, CONFIG), TRUE),
  15273. X        exit (4);
  15274. X      fscanf (config, "%s %s\n", line, line);
  15275. X      if (!re_strcmp (values[i], upcase (line), NULL))
  15276. X        report_progress (report, tsprintf ("\nsys_config(): %s not a valid \
  15277. Xdefault value for %s in %s", line, options[i], CONFIG), TRUE),
  15278. X        exit (4);
  15279. X      strcpy (sys->lists[id].defaults.set_values[i], line);
  15280. X    }
  15281. X      }
  15282. X      if (feof (config) && strcmp (sys->arg, "}"))
  15283. X    report_progress (report, tsprintf ("\nsys_config(): Missing '}' for \
  15284. X'default'  for list %s in %s", sys->lists[id].alias, CONFIG), TRUE),
  15285. X    exit (4);
  15286. X    }
  15287. X    else if (!strcmp (cmd, "precedence"))
  15288. X      sscanf (args, "%s", sys->mail.precedence);
  15289. X    else if (!strcmp (cmd, "fax"))
  15290. X      strcpy (sys->fax.prog, args);
  15291. X    else if (!strcmp (cmd, "archive")) {
  15292. X      /* USER CONTRIBUTED CODE: Warren Burstein
  15293. X         "archive list dir spec [farch-dir] [password] [digest]"
  15294. X     
  15295. X         dir must be an absolute path
  15296. X       
  15297. X         farch-dir should be relative to HOMEDIR/archives
  15298. X         so we can create all the INDEX files
  15299. X       
  15300. X         if you don't want digests but do want farch-dir, set the field
  15301. X         to anything but digest, if you don't want farch-dir just omit it.
  15302. X      */
  15303. X      char digest [MAX_LINE];
  15304. X
  15305. X      RESET (digest);
  15306. X      sscanf (args, "%s ", sys->arg);
  15307. X      upcase (sys->arg);
  15308. X      id = get_list_id (sys->arg, sys, nlists);
  15309. X      if (id < 0)
  15310. X        report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
  15311. Xname %s for 'archive' in %s", sys->arg, CONFIG), TRUE),
  15312. X        exit (4);
  15313. X      sys->lists[id].options |= ARCHIVE_LIST;
  15314. X      sscanf (args, "%s %s %s %s %s %s",
  15315. X              sys->arg, sys->lists[id].arch_dir, sys->lists[id].arch_spec,
  15316. X              sys->lists[id].farch_dir, sys->lists[id].arch_pass, digest);
  15317. X
  15318. X      locase (sys->lists[id].arch_spec);
  15319. X      if (*sys->lists[id].arch_dir != '/') {
  15320. X        report_progress (report, tsprintf ("\nsys_config(): archive-dir for %s \
  15321. Xdoesn't start with /",
  15322. X                       sys->arg, CONFIG), TRUE),
  15323. X        exit (4);
  15324. X      }
  15325. X
  15326. X      if (*sys->lists[id].farch_dir == '/') {
  15327. X        report_progress (report, tsprintf ("\nsys_config(): farch-dir for %s \
  15328. Xstarts with /",
  15329. X                       sys->arg, CONFIG), TRUE),
  15330. X        exit (4);
  15331. X      }
  15332. X
  15333. X      if (*sys->lists[id].farch_dir == '-' || *sys->lists[id].farch_dir == EOS)
  15334. X    sprintf (sys->lists[id].farch_dir, DEFAULT_ARCHIVE);
  15335. X
  15336. X      if (!strcmp (sys->lists[id].arch_pass, "-"))
  15337. X    RESET (sys->lists[id].arch_pass);
  15338. X
  15339. X      if (!strcmp (locase (digest), "digest"))
  15340. X    sys->lists[id].options |= ARCHIVE_DIGEST;
  15341. X    }
  15342. X    else if (!strcmp (cmd, "unix_cmd")) {
  15343. X      sscanf (args, "%s", sys->arg);
  15344. X      upcase (sys->arg);
  15345. X      id = get_list_id (sys->arg, sys, nlists);
  15346. X      if (id < 0)
  15347. X    report_progress (report, tsprintf ("\nsys_config(): Unrecognized list \
  15348. Xname %s for 'unix_cmd' in %s", sys->arg, CONFIG), TRUE),
  15349. X    exit (4);
  15350. X      RESET (arg);
  15351. X      sscanf (args, "%s %s", sys->arg, arg);
  15352. X      if (arg[0] == EOS || arg[0] == '#' || arg[0] == '\'')
  15353. X    report_progress (report, tsprintf ("\nsys_config(): Missing or invalid \
  15354. Xpassword %s for 'unix_cmd' in %s", arg, CONFIG), TRUE),
  15355. X    exit (4);
  15356. X      if ((unix_cmd = (_CMDS *) malloc (sizeof (*unix_cmd))) == NULL)
  15357. X    report_progress (report, tsprintf ("\nsys_config(): malloc() failed \
  15358. Xduring 'unix_cmd' in %s", CONFIG), TRUE),
  15359. X    exit (11);
  15360. X      strcpy (unix_cmd->password, arg);
  15361. X      upcase (unix_cmd->password);
  15362. X      RESET (arg);
  15363. X      sscanf (args, "%s %s %s", sys->arg, sys->arg, arg);
  15364. X      if (arg[0] == EOS || arg[0] == '#' || arg[0] == '\'')
  15365. X    report_progress (report, tsprintf ("\nsys_config(): Missing or invalid \
  15366. Xcommand name %s for 'unix_cmd' in %s", arg, CONFIG), TRUE),
  15367. X    exit (4);
  15368. X      strcpy (unix_cmd->name, arg);
  15369. X      upcase (unix_cmd->name);
  15370. X      start = strchr (args, '\'');
  15371. X      end = strrchr (args, '\'');
  15372. X      if (!start || !end || start == end)
  15373. X    report_progress (report, tsprintf ("\nsys_config(): Missing ''' for \
  15374. X'unix_cmd' in %s",
  15375. X                       CONFIG), TRUE),
  15376. X    exit (4);
  15377. X      if (! (unix_cmd->cmd =
  15378. X      (char *) malloc ((abs (end - start - 1) + 1) * sizeof (char))))
  15379. X    report_progress (report, tsprintf ("\nsys_config(): malloc() failed \
  15380. Xduring 'unix_cmd' in %s", CONFIG), TRUE),
  15381. X    exit (11);
  15382. X      strncpy (unix_cmd->cmd, start + 1, abs (end - start - 1));
  15383. X      unix_cmd->cmd[abs (end - start - 1)] = EOS;
  15384. X      if (!(comment = strchr (args, '#')))
  15385. X    report_progress (report, tsprintf ("\nsys_config(): Missing '#' for \
  15386. X'unix_cmd' in %s",
  15387. X                       CONFIG), TRUE),
  15388. X    exit (4);
  15389. X      if (! (unix_cmd->comment =
  15390. X      (char *) malloc ((strlen (comment + 1) + 1) * sizeof (char))))
  15391. X    report_progress (report, tsprintf ("\nsys_config(): malloc() failed \
  15392. Xduring 'unix_cmd' in %s", CONFIG), TRUE),
  15393. X    exit (11);
  15394. X      strcpy (unix_cmd->comment, comment + 1);
  15395. X      unix_cmd->next = sys->lists[id].unix_cmds;
  15396. X      sys->lists[id].unix_cmds = unix_cmd;
  15397. X    }
  15398. X    else
  15399. X      report_progress (report, tsprintf ("\nsys_config(): Unrecognized \
  15400. Xdirective %s in %s", cmd, CONFIG), TRUE),
  15401. X      exit (4);
  15402. X  }
  15403. X  fclose (config);
  15404. X  config_owner_prefs (sys, nlists, report);
  15405. X  return nlists;
  15406. X}
  15407. X
  15408. X/*
  15409. X  Get owner and manager preferences from OWNERSF.
  15410. X
  15411. X  Enhanced by: Warren Burstein.
  15412. X*/
  15413. X
  15414. Xvoid config_owner_prefs (SYS *sys, int nlists, FILE *report)
  15415. X{
  15416. X  FILE *f;
  15417. X  char registered_owner [MAX_LINE];
  15418. X  char assigned_list [MAX_LINE];
  15419. X  char pref [MAX_OWNER_PREFS] [MAX_LINE];
  15420. X  char prefs [MAX_LINE];
  15421. X  int listid, i, *op;
  15422. X
  15423. X  OPEN_FILE (f, OWNERSF, "r", "config_owner_prefs");
  15424. X  while (!feof (f)) {
  15425. X    assigned_list[0] = RESET (prefs);
  15426. X    fscanf (f, "%s %s", registered_owner, assigned_list);
  15427. X    upcase (assigned_list);
  15428. X    fgets (prefs, MAX_LINE - 2, f);
  15429. X    if (assigned_list [0] != EOS && registered_owner[0] != '#') {
  15430. X      for (i = 0; i < MAX_OWNER_PREFS; i++)
  15431. X    RESET (pref [i]);
  15432. X      sscanf (prefs, "%s %s %s %s %s %s %s %s", pref [0], pref [1], pref [2],
  15433. X          pref [3], pref [4], pref [5], pref [6], pref [7]);
  15434. X      if (!strcmp (assigned_list, "SERVER"))
  15435. X    op = &(sys->server.manager_prefs);
  15436. X      else if ((listid = get_list_id (assigned_list, sys, nlists)) >= 0)
  15437. X    op = &(sys->lists[listid].owner_prefs);
  15438. X      else
  15439. X    report_progress (report, tsprintf ("\nconfig_owner_prefs(): Unknown \
  15440. Xlist %s in %s",
  15441. X                       assigned_list, OWNERSF), TRUE),
  15442. X    exit (4);
  15443. X      for (i = 0; i < MAX_OWNER_PREFS && pref [i][0] != EOS; i++) {
  15444. X    /* Undocumented: also support -CCxxx systax: keni@oasys.dt.navy.mil */
  15445. X    char *pi = pref[i];
  15446. X    int pil = strlen (pi);
  15447. X    int neg = 0;
  15448. X    if (pi[0] == '-')
  15449. X      neg = 1,
  15450. X      --pil,
  15451. X      ++pi,
  15452. X      *op = ~*op;
  15453. X    if (!strncmp (pi, CCALL, pil))
  15454. X      *op |= ccall;
  15455. X    else if (!strncmp (pi, CCERRORS, pil))
  15456. X      *op |= ccerrors;
  15457. X    else if (!strncmp (pi, CCSUB, pil))
  15458. X      *op |= ccsub;
  15459. X    else if (!strncmp (pi, CCUNSUB, pil))
  15460. X      *op |= ccunsub;
  15461. X    else if (!strncmp (pi, CCSET, pil))
  15462. X      *op |= ccset;
  15463. X    else if (!strncmp (pi, CCREC, pil))
  15464. X      *op |= ccrec;
  15465. X    else if (!strncmp (pi, CCINFO, pil))
  15466. X      *op |= ccinfo;
  15467. X    else if (!strncmp (pi, CCSTAT, pil))
  15468. X      *op |= ccstat;
  15469. X    else if (!strncmp (pi, CCGET, pil))
  15470. X      *op |= ccget;
  15471. X    else if (!strncmp (pi, CCINDEX, pil))
  15472. X      *op |= ccindex;
  15473. X    else if (!strncmp (pi, CCLISTS, pil))
  15474. X      *op |= cclists;
  15475. X    else if (!strncmp (pi, CCRELEASE, pil))
  15476. X      *op |= ccrelease;
  15477. X    else if (!strncmp (pi, CCHELP, pil))
  15478. X      *op |= cchelp;
  15479. X    else if (!strncmp (pi, CCPRIVATE, pil))
  15480. X      *op |= ccprivate;
  15481. X    else if (!strncmp (pi, CCRUN, pil))
  15482. X      *op |= ccrun;
  15483. X    else if (pref [i][0] != EOS)
  15484. X      report_progress (report, tsprintf ("\nconfig_owner_prefs(): Unknown \
  15485. Xpreference %s in %s",
  15486. X                         pref [i], OWNERSF), TRUE),
  15487. X      exit (4);
  15488. X    if (neg)
  15489. X      *op = ~*op;
  15490. X      }
  15491. X    }
  15492. X  }
  15493. X  fclose (f);
  15494. X}
  15495. X
  15496. X/*
  15497. X  Convert a string to lower case.
  15498. X*/
  15499. X
  15500. Xchar *locase (char *s)
  15501. X{
  15502. X  char *r = s;
  15503. X  while (*s != EOS) {
  15504. X    if (isupper (*s))
  15505. X      *s = (char) tolower (*s);
  15506. X    ++s;
  15507. X  }
  15508. X  return r;
  15509. X}
  15510. X
  15511. X/*
  15512. X  Convert a string to upper case.
  15513. X*/
  15514. X
  15515. Xchar *upcase (char *s)
  15516. X{
  15517. X  char *r = s;
  15518. X
  15519. X  while (*s != EOS) {
  15520. X    if (islower (*s))
  15521. X      *s = (char) toupper (*s);
  15522. X    ++s;
  15523. X  }
  15524. X  return r;
  15525. X}
  15526. X
  15527. X/*
  15528. X  Replace all characters of the first word in 's' with "X".
  15529. X*/
  15530. X
  15531. Xvoid shadow_password (char *s)
  15532. X{
  15533. X  while (*s != EOS && isspace (*s)) /* Get to first word */
  15534. X    ++s;
  15535. X  if (*s != EOS)
  15536. X    while (!isspace (*s))
  15537. X      *s = 'X',
  15538. X      ++s;
  15539. X}
  15540. X
  15541. X/*
  15542. X  Write messages and times to 'report' and stdout. If 'report_time'
  15543. X  is set to a negative value no leading newline is printed to 'report'.
  15544. X  NOTE: Use strftime(), if possible.
  15545. X*/
  15546. X
  15547. Xvoid report_progress (FILE *report, char *s, int report_time)
  15548. X{
  15549. X#ifdef SYSLOG
  15550. X  char *buf;
  15551. X  int i, j;
  15552. X
  15553. X  if (!(buf = (char *) malloc ((strlen (s) + 1) * sizeof (char))))
  15554. X    gexit (11);
  15555. X  strcpy (buf, s);
  15556. X  for (i = 0; i < strlen (buf); i++) {
  15557. X    if (buf [i] == '\n')
  15558. X      buf [i] = ' ';
  15559. X    if (buf [i] == '%' && buf [i + 1] != '%') {
  15560. X      if ((buf = (char *) realloc (buf, (strlen (buf) + 2) * sizeof (char))) ==
  15561. X      NULL)
  15562. X    gexit (11);
  15563. X      for (j = strlen (buf); j >= i; j--)
  15564. X    buf [j + 1] = buf [j];
  15565. X      ++i;
  15566. X    }
  15567. X  }
  15568. X  syslog (LOG_INFO, buf);
  15569. X  free ((char *) buf);
  15570. X#else
  15571. X  extern BOOLEAN tty_echo;
  15572. X# ifdef ultrix
  15573. X  time_t time_is = 0;
  15574. X# else
  15575. X  long int time_is = 0;
  15576. X# endif
  15577. X  struct tm *t;
  15578. X
  15579. X  if (report) {
  15580. X    fprintf (report, "%s", s);
  15581. X    if (report_time) {
  15582. X      time (&time_is);
  15583. X      t = localtime (&time_is);
  15584. X      if (report_time > 0)
  15585. X    fprintf (report, "\n");
  15586. X      fprintf (report, "Time/Date: %2d:%.2d:%.2d, %2d/%.2d/%2d\n",
  15587. X           t->tm_hour, t->tm_min, t->tm_sec, t->tm_mon + 1, t->tm_mday,
  15588. X           t->tm_year);
  15589. X    }
  15590. X    fflush (report);
  15591. X  }
  15592. X  if (tty_echo) {
  15593. X    printf ("%s", s);
  15594. X    if (report_time)
  15595. X      printf ("\n");
  15596. X    fflush (stdout);
  15597. X  }
  15598. X#endif
  15599. X}
  15600. X
  15601. X/*
  15602. X  Start distribution. Call lower level routines; the algorithm is such that
  15603. X  this routine always looks at the beginning of each message when reading
  15604. X  into 'first_line', i.e. 'first_line' is always assigned a string of the form:
  15605. X        'From emailaddress Date Time'
  15606. X  which is the universal convention for the start of every message. It calls
  15607. X  subscribed() to find out if the sender is subscribed and passes the
  15608. X  result to process_message(). Since the call to extract_sender() alters
  15609. X  'first_line' to contain only the sender's email address a 'linecopy' is used.
  15610. X  When returning from process_message() we have already advanced to the
  15611. X  beginning of the next message, and 'linecopy' contains a string of the 
  15612. X  above form; therefore we need to copy that back to 'first_line'.
  15613. X*/
  15614. X
  15615. Xvoid distribute (FILE *mail, void (*process_message)(), FILE *report,
  15616. X         char *Subscribersf, char *Newsf, char *Peersf, char *Aliasesf,
  15617. X         BOOLEAN block_sem)
  15618. X{
  15619. X  char first_line[MAX_LINE], linecopy[MAX_LINE];
  15620. X  BOOLEAN address_status;
  15621. X
  15622. X  first_line[0] = RESET (linecopy);
  15623. X  while (!feof (mail))
  15624. X    if (first_line[0] != EOS)
  15625. X      address_status = extract_sender (first_line),
  15626. X      process_message ((char *) first_line, (char *) linecopy,
  15627. X               (BOOLEAN) address_status,
  15628. X               (BOOLEAN)
  15629. X                subscribed (report, first_line, Subscribersf, Newsf,
  15630. X                    Peersf, Aliasesf, block_sem)),
  15631. X      strcpy (first_line, linecopy);
  15632. X    else /* Read the first line of the very first message */
  15633. X      fgets (first_line, MAX_LINE - 2, mail), /* 'From email Date Time' */
  15634. X      strcpy (linecopy, first_line);
  15635. X}
  15636. X
  15637. X/*
  15638. X  Look for occurence of 'string' in 'substr' and return either TRUE or FALSE.
  15639. X  Look at the comments for defs.h for the syntax of 'substr'. A 'substr' of
  15640. X  ".*" matches everything.
  15641. X*/
  15642. X
  15643. XBOOLEAN strinstr (char *substr, char *string)
  15644. X{
  15645. X  char *substrcopy, *stringcopy;
  15646. X  extern FILE *report;
  15647. X
  15648. X  substrcopy = (char *) malloc ((strlen (substr) + 1) * sizeof (char));
  15649. X  stringcopy = (char *) malloc ((strlen (string) + 1) * sizeof (char));
  15650. X  if (!substrcopy || !stringcopy)
  15651. X    report_progress (report, "\nstrinstr(): malloc() failed", TRUE),
  15652. X    gexit (11);
  15653. X  strcpy (substrcopy, substr);
  15654. X  strcpy (stringcopy, string);
  15655. X  upcase (substrcopy);
  15656. X  upcase (stringcopy);
  15657. X  if (re_strcmp (substrcopy, stringcopy, NULL) > 0) {
  15658. X    free ((char *) substrcopy);
  15659. X    free ((char *) stringcopy);
  15660. X    return TRUE;
  15661. X  }
  15662. X  free ((char *) stringcopy);
  15663. X  free ((char *) substrcopy);
  15664. X  return FALSE;
  15665. X}
  15666. X
  15667. X/*
  15668. X  Given a file path, extract the file name. In the process, any command line
  15669. X  options or any characters separated from the filename are discarded.
  15670. X*/
  15671. X
  15672. Xchar *extract_filename (char *s)
  15673. X{
  15674. X  char *p, *r, *t = s, nchar = 0;
  15675. X  extern FILE *report;
  15676. X
  15677. X  while (*t != EOS && *t != ' ' && *t != '\t') /* Get to delimiting char */
  15678. X    ++t;
  15679. X  while (t != s && *t != '/') /* Go back till / or the beginning of s */
  15680. X    ++nchar,
  15681. X    --t;
  15682. X  if (t != s || (*t == '/' && *(t + 1) != EOS))
  15683. X    --nchar,
  15684. X    ++t;
  15685. X  if (! (r = p = (char *) malloc ((nchar + 1) * sizeof (char))))
  15686. X    report_progress (report, "\nextract_filename(): malloc() failed", TRUE),
  15687. X    gexit (11);
  15688. X  *p = EOS;
  15689. X  while (*t != EOS && *t != ' ' && *t != '\t')
  15690. X    *(p++) = *(t++);
  15691. X  *p = EOS;
  15692. X  return r;
  15693. X}
  15694. X
  15695. X/*
  15696. X  Recognize the command line parameters. It returns '?' on an unrecognized
  15697. X  option, ':' if an option requires an argument and the argument is missing,
  15698. X  or the recognized character itself. This code is a copyright of AT&T.
  15699. X*/
  15700. X
  15701. X# define ERR(str, ch) if (opterr) \
  15702. X                        fprintf (stderr, "%s%s%c\n", argv[0], str, ch);
  15703. X
  15704. X#ifdef linux
  15705. Xint _getopt (int argc, char **argv, char *opts)
  15706. X{
  15707. X  return getopt(argc, argv, opts);
  15708. X}
  15709. X#else
  15710. Xint _getopt (int argc, char **argv, char *opts)
  15711. X{
  15712. X  static int sp = 1;
  15713. X  register int c;
  15714. X  register char *cp;
  15715. X  extern int opterr, optind, optopt;
  15716. X  extern char *optarg;
  15717. X
  15718. X  if (sp == 1)
  15719. X    if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
  15720. X      return EOF;
  15721. X    else if (!strcmp (argv[optind], "--")) {
  15722. X      optind++;
  15723. X      return EOF;
  15724. X    }
  15725. X    optopt = c = argv[optind][sp];
  15726. X    if (c == ':' || (cp = strchr (opts, c)) == NULL) {
  15727. X      ERR (": unknown option, -", c);
  15728. X      if (argv[optind][++sp] == '\0')
  15729. X        optind++,
  15730. X        sp = 1;
  15731. X      return '?';
  15732. X    }
  15733. X    if (*++cp == ':') {
  15734. X      if (argv[optind][sp+1] != '\0')
  15735. X        optarg = &argv[optind++][sp+1];
  15736. X      else if (++optind >= argc) {
  15737. X        ERR(": argument missing for -", c);
  15738. X        sp = 1;
  15739. X        return ':';
  15740. X      }
  15741. X      else
  15742. X        optarg = argv[optind++];
  15743. X      sp = 1;
  15744. X    }
  15745. X    else {
  15746. X      if (argv[optind][++sp] == '\0')
  15747. X        sp = 1,
  15748. X        optind++;
  15749. X      optarg = NULL;
  15750. X    }
  15751. X    return c;
  15752. X}
  15753. X#endif
  15754. X
  15755. X/*
  15756. X  Remove any extraneous characters from a name and convert it to lower
  15757. X  case with the first character of each word capitalized [currently disbled].
  15758. X*/
  15759. X
  15760. Xchar *clean_name (char *s)
  15761. X{
  15762. X  char *tok, *copy, *sep = " ", *line;
  15763. X  int j, l;
  15764. X  extern FILE *report;
  15765. X
  15766. X  if (s [0] != EOS && s [strlen (s) - 1] == '\n')
  15767. X    s [strlen (s) - 1] = EOS;
  15768. X  if (! (line = (char *) malloc ((strlen (s) + 1) * sizeof (char))))
  15769. X    report_progress (report, "\nclean_name(): malloc() failed", TRUE),
  15770. X    gexit (11);
  15771. X  strcpy (line, s);
  15772. X  *s = EOS;
  15773. X  tok = strtok (line, sep);
  15774. X  while (tok) {
  15775. X    copy = tok;
  15776. X    while (*copy != EOS) {  /* Remove extraneous characters */
  15777. X      if (! isalpha (*copy) && ! isspace (*copy) && ! isdigit (*copy) &&
  15778. X      *copy != '-' && *copy != '.' && *copy != '@') {
  15779. X        for (j = 0, l = strlen (copy); j < l; copy [j] = copy [j + 1], ++j);
  15780. X        continue;
  15781. X      }
  15782. X      ++copy;
  15783. X    }
  15784. X    locase (tok);
  15785. X    *tok = (char) toupper (*tok);
  15786. X    sprintf (s + strlen (s), " %s", tok);
  15787. X    tok = strtok (NULL, sep);
  15788. X  }
  15789. X  free ((char *) line);
  15790. X  return s;
  15791. X}
  15792. X
  15793. X/*
  15794. X  Remove leading blanks and extraneous characters from a request.
  15795. X*/
  15796. X
  15797. Xvoid clean_request (char *s)
  15798. X{
  15799. X  while (isspace (*s))
  15800. X    sprintf (s, "%s", s + 1);
  15801. X  while (*s != EOS) {
  15802. X    if (*s < ' ' && *s != '\t' && *s != '\n' && *s != '\r')
  15803. X      *s = EOS;
  15804. X    ++s;
  15805. X  }
  15806. X}
  15807. X
  15808. X/*
  15809. X  Identify the list that the request refers to. Before doing so, remove
  15810. X  any unnecessary blanks from the parameters. Also, check each parameter
  15811. X  for proper syntax.
  15812. X*/
  15813. X
  15814. Xvoid get_list_name (char *params, char *list_name)
  15815. X{
  15816. X  int i;
  15817. X  char *s, *r, *t;
  15818. X  char param [MAX_LINE];
  15819. X  extern FILE *report;
  15820. X
  15821. X  if (! (r = s = (char *) malloc ((strlen (params) + 1) * sizeof (char))))
  15822. X    report_progress (report, "\nget_list_name(): malloc() failed", TRUE),
  15823. X    gexit (11);
  15824. X  strcpy (s, params);
  15825. X  param [0] = RESET (params);
  15826. X  for (i = 0; s[i] != EOS;)
  15827. X    if (isspace (s[i]) && isspace (s[i + 1]))
  15828. X      sprintf (s + i, "%s", s + i + 1);
  15829. X    else
  15830. X      i++;
  15831. X  do {
  15832. X    RESET (param);
  15833. X    sscanf (s, "%s", param);
  15834. X    s = s + strlen (param) + 1; /* Skip over space */
  15835. X    t = strpbrk (param, "*?/`");
  15836. X    if (t != NULL) {
  15837. X      if (t == param || (t != param && ! isalpha (*(t - 1)))) /* Invalid *,? */
  15838. X    *t = '#';
  15839. X      if (*t == '/') /* Invalid / */
  15840. X    *t = '%';
  15841. X      if (*t == '`') /* Invalid ` */
  15842. X    *t = '-';
  15843. X    }
  15844. X    sprintf (params + strlen (params), " %s", param);
  15845. X  } while (param[0] != EOS);
  15846. X  strcat (params, "\n");
  15847. X  free ((char *) r);
  15848. X  RESET (list_name);
  15849. X  sscanf (params, "%s", list_name);
  15850. X  upcase (list_name);
  15851. X  sprintf (params, "%s", params + strlen (list_name) + 1);
  15852. X}
  15853. X
  15854. X/*
  15855. X  Free the current list of matched remote lists.
  15856. X*/
  15857. X
  15858. Xvoid free_remote_matched (REMOTE **matched_rlists)
  15859. X{
  15860. X  REMOTE *next;
  15861. X
  15862. X  while (*matched_rlists)  /* Free old list */
  15863. X    next = (*matched_rlists)->next,
  15864. X    free ((REMOTE *) *matched_rlists),
  15865. X    *matched_rlists = next;
  15866. X}
  15867. X
  15868. X/*
  15869. X  Given a list name, return its index in the array of known lists. If the
  15870. X  list is a remote list, return nlists to signify this effect.
  15871. X*/
  15872. X
  15873. Xint get_list_id (char *list_name, SYS *sys, int nlists)
  15874. X{
  15875. X  int i;
  15876. X  char *p, address [MAX_LINE];;
  15877. X
  15878. X  free_remote_matched (&matched_rlists);
  15879. X  for (i = 0; i < nlists; i++) {
  15880. X    if (!strcmp (list_name, sys->lists[i].alias))
  15881. X      return i;
  15882. X    strcpy (address, sys->lists[i].address);
  15883. X    upcase (address);
  15884. X    if (!strcmp (list_name, address) && (p = strchr (list_name, '@'))) {
  15885. X      *p = EOS;
  15886. X      return i;
  15887. X    }
  15888. X  }
  15889. X  if (check_remote (rlists, list_name)) {
  15890. X    /* Store list name above all known lists */
  15891. X    strcpy (sys->lists[nlists].alias, list_name);
  15892. X    return nlists;
  15893. X  }
  15894. X  return -1;
  15895. X}
  15896. X
  15897. X/*
  15898. X  Check whether 'list_name' is a remote list. Return a linked list
  15899. X  of matched records, or NULL. The list is stored in the global variable
  15900. X  'matched_rlists'.
  15901. X*/
  15902. X
  15903. XREMOTE *check_remote (REMOTE *rlists, char *list_name)
  15904. X{
  15905. X  REMOTE *new;
  15906. X  char address [MAX_LINE];
  15907. X  extern FILE *report;
  15908. X
  15909. X  while (rlists) {
  15910. X    strcpy (address, rlists->address);
  15911. X    upcase (address);
  15912. X    if (!strcmp (list_name, rlists->alias) ||
  15913. X    !strcmp (list_name, address)) {
  15914. X      if ((new = (REMOTE *) malloc (sizeof (*new))) == NULL)
  15915. X    report_progress (report, "\ncheck_remote(): malloc() failed", TRUE),
  15916. X    gexit (11);
  15917. X      memcpy ((char *) new, (char *) rlists, sizeof (*new));
  15918. X      new->next = matched_rlists;
  15919. X      matched_rlists = new;
  15920. X    }
  15921. X    rlists = rlists->next;
  15922. X  }
  15923. X  return matched_rlists;
  15924. X}
  15925. X
  15926. Xvoid setup_string (char *s, char *alias, char *filename)
  15927. X{
  15928. X  RESET (s);
  15929. X  SETUP_STRING;
  15930. X}
  15931. X
  15932. X/*
  15933. X  Return the first occurence of 'sub' in 'src', or NULL if not found.
  15934. X*/
  15935. X
  15936. Xchar *_strstr (char *src, char *sub)
  15937. X{
  15938. X  if (src == NULL || sub == NULL)
  15939. X    return NULL;
  15940. X  while (*src != EOS) {
  15941. X    if (!strncmp (src, sub, strlen (sub)))
  15942. X      return src;
  15943. X    ++src;
  15944. X  }
  15945. X  return NULL;
  15946. X}
  15947. X
  15948. X/*
  15949. X  Shrink a file so that it contains a maximum of MAX_FILE_LENGTH entries in it.
  15950. X*/
  15951. X
  15952. Xvoid shrink (char *s)
  15953. X{
  15954. X  struct stat buf;
  15955. X  char *tmpmsg;
  15956. X
  15957. X  if (s[0] == EOS || stat (s, &buf))
  15958. X    return;
  15959. X  syscom ("tail -%d %s > %s", MAX_FILE_LENGTH, s,
  15960. X      (tmpmsg = mystrdup (tmpnam (NULL))));
  15961. X  mv (tmpmsg, s);
  15962. X  free ((char *) tmpmsg);
  15963. X}
  15964. X
  15965. X/*
  15966. X  Verify that part 'i' (of a file split into different parts by farch)
  15967. X  is in 's'.
  15968. X*/
  15969. X
  15970. XBOOLEAN requested_part (char *s, int i)
  15971. X{
  15972. X  char buf [80];
  15973. X  char copy [MAX_LINE];
  15974. X
  15975. X  strncpy (copy, s, MAX_LINE - 1);
  15976. X  copy [MAX_LINE - 1] = EOS;
  15977. X  do {
  15978. X    RESET (buf);
  15979. X    sscanf (copy, "%s", buf);
  15980. X    sprintf (copy, "%s", strchr (copy, buf[0]) + strlen (buf));
  15981. X    if (atoi (buf) == i)
  15982. X      return TRUE;
  15983. X  } while (buf[0] != EOS);
  15984. X  return FALSE;
  15985. X}
  15986. X
  15987. X/*
  15988. X  Free the REMOTE linked list.
  15989. X*/
  15990. X
  15991. Xvoid free_remote (REMOTE **rlists)
  15992. X{
  15993. X  REMOTE *next;
  15994. X
  15995. X  while (*rlists)
  15996. X    next = (*rlists)->next,
  15997. X    free ((REMOTE *) *rlists),
  15998. X    *rlists = next;
  15999. X  *rlists = NULL;
  16000. X}
  16001. X
  16002. X/*
  16003. X  Use my_system() when either list and listproc use TELNET and there is
  16004. X  an indication that the sessions do not exit.
  16005. X*/
  16006. X
  16007. Xint my_system (char *s)
  16008. X{
  16009. X  FILE *f;
  16010. X  int pid, status;
  16011. X  char line [MAX_LINE], *r;
  16012. X  extern SYS sys;
  16013. X
  16014. X  if (strcmp ((r = extract_filename (s)), "telnet")) {
  16015. X    status = system (s);
  16016. X    free ((char *) r);
  16017. X    return status;
  16018. X  }
  16019. X  free ((char *) r);
  16020. X  strcat (s, " &"); /* Only telnet runs in the background */
  16021. X  status = system (s);
  16022. X  if (status > 127)
  16023. X    return status;
  16024. X  sleep (5);
  16025. X  if (sys.options & BSD_PS)
  16026. X    system ("ps -gx | grep telnet | grep -v \"grep telnet\" \
  16027. X        | grep -v telnetd > ./telnet");
  16028. X  else if (sys.options & SYSV_PS)
  16029. X    system ("ps -ef | grep telnet | grep -v \"grep telnet\" \
  16030. X        | grep -v telnetd > ./telnet");
  16031. X  if ((f = fopen ("./telnet", "r")) == NULL)
  16032. X    return -1;
  16033. X  while (! feof (f)) {
  16034. X    RESET (line);
  16035. X    fgets (line, MAX_LINE - 2, f);
  16036. X    if (line[0] != EOS)
  16037. X      sscanf (line, "%d", &pid),
  16038. X      sleep (15),
  16039. X      kill (pid, SIGHUP);
  16040. X  }
  16041. X  fclose (f);
  16042. X  unlink ("./telnet");
  16043. X  return status;
  16044. X}
  16045. X
  16046. X/* Change history (by Bob Boyd)
  16047. X21-Aug-1991   RLB     change parameter scanning for "list" lines in the
  16048. X                      config file so that "-" characters in the list-alias
  16049. X                      are ignored when looking for the beginning of the
  16050. X                      list parameters [tasos: I defined my own strstr()]
  16051. X*/
  16052. X
  16053. X/*
  16054. X  Remove the message identified as 'tag_to_remove' from the specified 'file'.
  16055. X  Return TRUE if successful, FALSE if the message was not located.
  16056. X*/
  16057. X
  16058. XBOOLEAN remove_msg (char *file, int tag_to_remove, FILE *report)
  16059. X{
  16060. X  FILE *in, *out;
  16061. X  char prev_line [MAX_LINE];
  16062. X  char line [MAX_LINE];
  16063. X  char match [MAX_LINE];
  16064. X  char *tmp_moderated_f;
  16065. X  BOOLEAN copy = FALSE, message_found = FALSE;
  16066. X  int tag;
  16067. X
  16068. X  mv (file, (tmp_moderated_f = mystrdup (tmpnam (NULL))));
  16069. X  chmod (tmp_moderated_f, 416); /* 640 */
  16070. X  OPEN_FILE (in, tmp_moderated_f, "r", "remove_msg");
  16071. X  OPEN_FILE (out, file, "w", "remove_msg");
  16072. X  prev_line[0] = RESET (line);
  16073. X  while (!feof (in)) {
  16074. X    if (!strncmp (line, START_OF_MESSAGE, strlen (START_OF_MESSAGE)) &&
  16075. X    !copy)
  16076. X      RESET (prev_line),
  16077. X      copy = TRUE;
  16078. X    strcpy (match, "\\1");
  16079. X    if (re_strcmp (MESSAGE_TAG, line, match) > 0) { /* Get tag # */
  16080. X      sprintf (line, "%s", line + strlen (match));
  16081. X      sscanf (line, "%d", &tag);
  16082. X      sprintf (line, "%s%d\n", match, tag);
  16083. X      if (tag_to_remove == tag)
  16084. X    message_found = TRUE,
  16085. X    copy = FALSE;
  16086. X    }
  16087. X    if (copy && prev_line[0] != EOS)
  16088. X      fprintf (out, "%s", prev_line);
  16089. X    strcpy (prev_line, line);
  16090. X    RESET (line);
  16091. X    fgets (line, MAX_LINE - 2, in);
  16092. X  }
  16093. X  if (copy && prev_line[0] != EOS)
  16094. X    fprintf (out, "%s", prev_line);
  16095. X  fclose (in);
  16096. X  fclose (out);
  16097. X  unlink (tmp_moderated_f);
  16098. X  free ((char *) tmp_moderated_f);
  16099. X  return message_found;
  16100. X}
  16101. X
  16102. X/*
  16103. X  Read the parameters from 'line' that follow 'request' in 'line',
  16104. X  and possibly from lines below in the 'mail' file, if 'line' ends
  16105. X  with &. Continuation lines should always end with '&' and no
  16106. X  trailing blanks or any other characters except new-line.
  16107. X  'params' should end with a \n.
  16108. X*/
  16109. X
  16110. Xvoid read_params (char *line, char *params, char *request, FILE *mail,
  16111. X          FILE *report)
  16112. X{
  16113. X  char l [MAX_LINE];
  16114. X
  16115. X  sprintf (params, "%s", line + strlen (request));
  16116. X  if (params [strlen (params) - 1] == '\n')
  16117. X    params [strlen (params) - 1] = EOS; /* Remove trailing \n */
  16118. X  RESET (l);
  16119. X  while (!feof (mail) &&
  16120. X     strncmp (l, START_OF_MESSAGE, strlen (START_OF_MESSAGE)) &&
  16121. X     params [0] != EOS && params [strlen (params) - 1] == '&') {
  16122. X    params [strlen (params) - 1] = EOS; /* Replace & */
  16123. X    RESET (l);
  16124. X    fgets (l, MAX_LINE - 2, mail);
  16125. X    if (l [0] != EOS &&
  16126. X    strncmp (l, START_OF_MESSAGE, strlen (START_OF_MESSAGE))) {
  16127. X      if (report)
  16128. X    report_progress (report, l, FALSE);
  16129. X      l [strlen (l) - 1] = EOS, /* Remove trailing \n */
  16130. X      strcat (params, l);
  16131. X    }
  16132. X  }
  16133. X  strcat (params, "\n");
  16134. X  if (!strncmp (l, START_OF_MESSAGE, strlen (START_OF_MESSAGE)))
  16135. X    fseek (mail, -strlen (l), SEEK_CUR); /* Move back to beginning of new msg */
  16136. X}
  16137. X
  16138. X/*
  16139. X  Open and lock file. It returns the opened file descriptor, or
  16140. X  CANT_OPEN or CANT_LOCK.
  16141. X
  16142. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  16143. X*/
  16144. X
  16145. Xint lock_file (char *file, int flag, int mode, BOOLEAN delay)
  16146. X{
  16147. X#ifdef NO_LOCKS
  16148. X  return 0;
  16149. X#else
  16150. X  int count, fd, lock;
  16151. X
  16152. X  if ((fd = open (file, flag, mode)) < 0)
  16153. X    return CANT_OPEN;
  16154. X  for (count = 0; (lock = lockf (fd, F_TLOCK, 0)) && (count < 180) && delay;
  16155. X       ++count, sleep (1));
  16156. X  if (lock) {
  16157. X    close (fd); 
  16158. X    return CANT_LOCK;
  16159. X  }
  16160. X  return fd;
  16161. X#endif
  16162. X}
  16163. X
  16164. X/*
  16165. X  Unlock and close the specified file descriptor.
  16166. X
  16167. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  16168. X*/
  16169. X
  16170. Xvoid unlock_file (int fd)
  16171. X{
  16172. X#ifndef NO_LOCKS
  16173. X  if (fd >= 0)
  16174. X    lockf (fd, F_ULOCK, 0),
  16175. X    close (fd);
  16176. X#endif
  16177. X}
  16178. X
  16179. X/*
  16180. X  Write to a non-blocking file descriptor.
  16181. X*/
  16182. X
  16183. Xlong int write_to_fd (int fd, char *buf, long int bytes_to_write)
  16184. X{
  16185. X  long int bytes_written, total_bytes = 0;
  16186. X  extern FILE *report;
  16187. X  char ch;
  16188. X  int mask;
  16189. X
  16190. X  errno = 0;
  16191. X#ifndef NO_ABORT_OP
  16192. X  if (fcntl (fd, F_SETFL, (mask = fcntl (fd, F_GETFL, 0)) | O_NDELAY) < 0
  16193. X# ifdef ENOTSOCK
  16194. X      && errno != ENOTSOCK
  16195. X# endif
  16196. X      )
  16197. X    report_progress (report, tsprintf ("\nwrite_to_fd(): fcntl() failed: \
  16198. Xerrno %d", errno), TRUE);
  16199. X#endif
  16200. X  while ((bytes_written = write (fd, buf, bytes_to_write)) < bytes_to_write) {
  16201. X    if (bytes_written < 0 && errno
  16202. X#ifdef ERESTART
  16203. X    && errno != ERESTART
  16204. X#endif
  16205. X    ) {
  16206. X      char error [256];
  16207. X      sprintf (error, "\nwrite_to_fd(): ");
  16208. X      switch (errno) {
  16209. X      case EWOULDBLOCK:
  16210. X#if (EWOULDBLOCK != EAGAIN)
  16211. X      case EAGAIN:
  16212. X#endif
  16213. X      case EINTR:
  16214. X#if defined (GO_INTERACTIVE) && !defined (NO_ABORT_OP)
  16215. X          if (recv (fd, &ch, 1, MSG_OOB | MSG_PEEK) > 0)
  16216. X        goto abort;
  16217. X#endif
  16218. X      continue;
  16219. X      case EBADF: strcat (error, "Bad file number"); break;
  16220. X      case EFAULT: strcat (error, "Bad address"); break;
  16221. X      case EFBIG: strcat (error, "File limit reached"); break;
  16222. X      case EINVAL: strcat (error, "Negative seek pointer"); break;
  16223. X      case EIO: strcat (error, "I/O error"); break;
  16224. X      case ENOSPC: strcat (error, "No space left on device"); break;
  16225. X      case ENXIO: strcat (error, "No such device or address"); break;
  16226. X      case ERANGE: sprintf (error + strlen (error), "Bytes to write (%ld) \
  16227. Xout of range", bytes_to_write); break;
  16228. X      case EPIPE: sprintf (error, "Client disappeared"); break;
  16229. X#ifdef ENETRESET
  16230. X      case ENETRESET: strcat (error, "Network dropped connection"); break;
  16231. X#endif
  16232. X      default: sprintf (error + strlen (error), "Error number %d", errno);
  16233. X      }
  16234. X      report_progress (report, error, TRUE);
  16235. X      if (bytes_written > 0)
  16236. X    total_bytes += bytes_written;
  16237. X#ifndef NO_ABORT_OP
  16238. X      if (fcntl (fd, F_SETFL, mask) < 0
  16239. X# ifdef ENOTSOCK
  16240. X      && errno != ENOTSOCK
  16241. X# endif
  16242. X      )
  16243. X    report_progress (report, tsprintf ("\nwrite_to_fd(): fcntl() failed: \
  16244. Xerrno %d", errno), TRUE);
  16245. X#endif
  16246. X      return (total_bytes > 0 ? -total_bytes : -1);
  16247. X    }
  16248. X    if (bytes_written > 0)
  16249. X      bytes_to_write -= bytes_written,
  16250. X      total_bytes += bytes_written,
  16251. X      buf += bytes_written;
  16252. X    errno = 0;
  16253. X  }
  16254. X  if (bytes_written > 0)
  16255. X    total_bytes += bytes_written;
  16256. X abort:
  16257. X#ifndef NO_ABORT_OP
  16258. X  if (fcntl (fd, F_SETFL, mask) < 0
  16259. X# ifdef ENOTSOCK
  16260. X      && errno != ENOTSOCK
  16261. X# endif
  16262. X      )
  16263. X    report_progress (report, tsprintf ("\nwrite_to_fd(): fcntl() failed: \
  16264. Xerrno %d", errno), TRUE);
  16265. X#endif
  16266. X  return total_bytes;
  16267. X}
  16268. X
  16269. X/*
  16270. X  Improved mkdir - builds all parents of full_path if needed.
  16271. X  If a mkdir fails, or a component of the directory exists but
  16272. X  is not a directory, return FALSE and store a description in report_msg.
  16273. X
  16274. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  16275. X*/
  16276. X
  16277. XBOOLEAN mkdir1 (char *full_path, char *report_msg, char *mask)
  16278. X{
  16279. X  BOOLEAN first = TRUE;
  16280. X  char *p = full_path, d[MAX_LINE], dir[MAX_LINE], head[MAX_LINE];
  16281. X  struct stat st;
  16282. X
  16283. X  RESET (head);
  16284. X  while (get_field (&p, '/', d)) {
  16285. X    if (first) {
  16286. X      first = FALSE;
  16287. X
  16288. X      if (d[0] == EOS) {
  16289. X    strcpy (head, "/");
  16290. X    continue;
  16291. X      }
  16292. X    }
  16293. X
  16294. X    sprintf (dir, "%s%s", head, d);
  16295. X    sprintf (head, "%s/", dir);
  16296. X
  16297. X    if (stat (dir, &st)) {
  16298. X      if (mkdir (dir, 0755 & (0755 ^ otoi (mask)))) {
  16299. X    sprintf (report_msg, "mkdir1(%s): mkdir %s failed, errno %d\n",
  16300. X         full_path, dir, errno);
  16301. X    return FALSE;
  16302. X      }
  16303. X    } 
  16304. X    else if ((st.st_mode & S_IFMT) != S_IFDIR) {
  16305. X      sprintf (report_msg, "mkdir1: %s is not a directory", dir);
  16306. X      return FALSE;
  16307. X    }
  16308. X  }
  16309. X  return TRUE;
  16310. X}
  16311. X
  16312. X/*
  16313. X  Convert an octal number stored in a string to integer.
  16314. X*/
  16315. X
  16316. Xint otoi (char *s)
  16317. X{
  16318. X  int i, n;
  16319. X
  16320. X  n = 0;
  16321. X  for (i = 0; s[i] >= '0' && s[i] <= '7'; ++i)
  16322. X    n = 8 * n + (s[i] - '0');
  16323. X  return n;
  16324. X}
  16325. X
  16326. X/*
  16327. X  Find a field in *src ending with "sep". Leave src pointing at char after sep,
  16328. X  store field in dst. If src points at end of string, return FALSE. If src
  16329. X  points at a separator, make dst a null string.
  16330. X
  16331. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  16332. X*/
  16333. X
  16334. XBOOLEAN get_field (char **src, char sep, char *dst)
  16335. X{
  16336. X  char *s = *src;
  16337. X  int len;
  16338. X
  16339. X  if (**src == EOS)
  16340. X    return FALSE;
  16341. X
  16342. X  while (**src != EOS && **src != sep)
  16343. X    ++*src;
  16344. X
  16345. X  if (*src == s) {
  16346. X    *dst = EOS;
  16347. X    if (**src != EOS)
  16348. X      ++*src;
  16349. X    return TRUE;
  16350. X  }
  16351. X
  16352. X  len = *src - s;
  16353. X  (void) strncpy (dst, s, len);
  16354. X  dst[len] = EOS;
  16355. X
  16356. X  if (**src != EOS)                  /* advance past separator */
  16357. X    ++*src;
  16358. X
  16359. X  return TRUE;
  16360. X}
  16361. X
  16362. X/*
  16363. X  Make the directory for dirf (a DIR file) and create/update all
  16364. X  necessary INDEX files.
  16365. X
  16366. X  USER CONTRIBUTED FUNCTION: Warren Burstein
  16367. X*/
  16368. X
  16369. XBOOLEAN make_indexes (char *dirf, char *farch_dir, char *password, char *error,
  16370. X              char *mask)
  16371. X{
  16372. X  char dirname [MAX_LINE], *p, *q;
  16373. X  struct dirmatch {
  16374. X    char *s;
  16375. X    BOOLEAN match;
  16376. X  } *dirs;
  16377. X  int n_dirs, i, j;
  16378. X  extern FILE *report;
  16379. X
  16380. X  /* Get the directory that INDEX/DIR is in and make it if needed. */
  16381. X  strcpy (dirname, dirf);
  16382. X  if (p = strrchr (dirname, '/'))
  16383. X   *p = EOS;
  16384. X  if (!mkdir1 (dirname, error, mask))
  16385. X    return FALSE;
  16386. X
  16387. X  /* The number of dirs is one higher than the number of slashes. Add one
  16388. X     more for the top level directory, ARCHIVE_DIR */
  16389. X  for (p = farch_dir, n_dirs = 2; *p != EOS; p++)
  16390. X    if (*p == '/')
  16391. X      ++n_dirs;
  16392. X
  16393. X  if (! (dirs = (struct dirmatch *) calloc (n_dirs, sizeof (dirs[0]))))
  16394. X    report_progress (report, "\nmake_indexes(): calloc() failed", TRUE),
  16395. X    gexit (11);
  16396. X
  16397. X  if (! (dirs[0].s =
  16398. X     (char *) malloc ((strlen (ARCHIVE_DIR) +
  16399. X               strlen (DEFAULT_ARCHIVE) + 2) * sizeof (char))))
  16400. X    report_progress (report, "\nmake_indexes(): malloc() failed", TRUE),
  16401. X    gexit (11);
  16402. X  sprintf (dirs[0].s, "%s/%s", ARCHIVE_DIR, DEFAULT_ARCHIVE);
  16403. X
  16404. X  for (i = 1, p = farch_dir; i < n_dirs; i++) {
  16405. X    int len;
  16406. X
  16407. X    /* Find end of the directory - slash or end of string */
  16408. X    for (q = p; *q != EOS && *q != '/'; q++);
  16409. X    len = q - p;
  16410. X
  16411. X    if (i == 1) {
  16412. X      if (! (dirs[i].s =
  16413. X         (char *) malloc ((strlen (ARCHIVE_DIR) + len + 2) *
  16414. X                  sizeof (char))))
  16415. X    report_progress (report, "\nmake_indexes(): malloc() failed", TRUE),
  16416. X    gexit (11);
  16417. X      sprintf (dirs[i].s, "%s/%.*s", ARCHIVE_DIR, len, p);
  16418. X    }
  16419. X    else {
  16420. X      if (! (dirs[i].s = (char *) malloc ((strlen (dirs[i - 1].s) + len + 2) *
  16421. X                      sizeof (char))))
  16422. X    report_progress (report, "\nmake_indexes(): malloc() failed", TRUE),
  16423. X    gexit (11);
  16424. X      sprintf (dirs[i].s, "%s/%.*s", dirs[i - 1].s, len, p);
  16425. X    }
  16426. X
  16427. X    /* In case there are extra slashes, skip them */
  16428. X    for (; *q != EOS && *q == '/'; q++);
  16429. X    p = q;
  16430. X
  16431. X    if (*p == EOS)
  16432. X      break;            /* premature end of string - too many /'s */
  16433. X  }
  16434. X
  16435. X  for (i = 0; i < n_dirs; i++) {
  16436. X    char indexf [MAX_LINE], dirf [MAX_LINE];
  16437. X    char line [MAX_LINE], arch [MAX_LINE], fullpath [MAX_LINE];
  16438. X    BOOLEAN missing;
  16439. X    FILE *fp;
  16440. X
  16441. X    if (!dirs[i].s)
  16442. X      continue;
  16443. X
  16444. X    /* Make INDEX and DIR files if not already there */
  16445. X    sprintf (indexf, "%s/%s", dirs[i].s, INDEX);
  16446. X    sprintf (dirf, "%s/%s", dirs[i].s, DIRF);
  16447. X    if (access (indexf, 0))
  16448. X      close (creat (indexf, 0644 & (0644 ^ otoi (mask))));
  16449. X    if (access (dirf, 0))
  16450. X      close (creat (dirf, 0644 & (0644 ^ otoi (mask))));
  16451. X
  16452. X    /* Read the index file for i, set match fields to TRUE for j >= i if dir
  16453. X       for j is not in there. */
  16454. X    OPEN_FILE (fp, indexf, "r", "make_indexes");
  16455. X
  16456. X    for (j = i; j < n_dirs; j++)
  16457. X      dirs[j].match = FALSE;
  16458. X
  16459. X    while (!feof (fp)) {
  16460. X      arch[0] = fullpath[0] = RESET (line);
  16461. X      fgets (line, MAX_LINE - 2, fp);
  16462. X      sscanf (line, "%s %s", arch, fullpath);
  16463. X      for (j = i; j < n_dirs; j++)
  16464. X        if (dirs[j].s && !strcmp (fullpath, dirs[j].s))
  16465. X          dirs[j].match = TRUE;
  16466. X    }
  16467. X    fclose (fp);
  16468. X
  16469. X    /* Set 'missing' if any j doesn't have match set. Add lines if missing. */
  16470. X    missing = FALSE;
  16471. X    for (j = i; j < n_dirs; j++)
  16472. X      if (!dirs[j].match)
  16473. X        missing = TRUE;
  16474. X
  16475. X    if (missing) {
  16476. X      OPEN_FILE (fp, indexf, "a", "make_indexes");
  16477. X      for (j = i; j < n_dirs; j++)
  16478. X        if (dirs[j].s && !dirs[j].match)
  16479. X          fprintf (fp, "%s %s %s\n", strrchr (dirs[j].s, '/') + 1, dirs[j].s,
  16480. X           (password ? password : ""));
  16481. X      fclose (fp);
  16482. X    }
  16483. X    free ((char *) dirs[i].s);
  16484. X  }
  16485. X  free ((struct dirmatch *) dirs);
  16486. X  return TRUE;
  16487. X}
  16488. X
  16489. X/*
  16490. X  Insert 'nwords' to 's' starting at 'index' in 'words'. Return the total
  16491. X  length of the words inserted; blanks are inserted between words.
  16492. X  While making space for the new words, 'replace' so many number of characters.
  16493. X*/
  16494. X
  16495. Xint insert_word (char *s, char **words, int nwords, int index, int replace)
  16496. X{
  16497. X  int i, j, nbytes = 0;
  16498. X  char *c = NULL;
  16499. X
  16500. X  for (i = 0; i < nwords; i++)
  16501. X    nbytes += strlen (words [index + i]);
  16502. X  if (nbytes < replace)
  16503. X    sprintf (s, "%s", s + replace - nbytes);
  16504. X  else
  16505. X    for (i = 0; i < nbytes - replace; i++)
  16506. X      for (c = s + strlen (s); c >= s + replace; c--)
  16507. X    *(c + 1) = *c;
  16508. X  for (i = 0, j = 0; i < nwords; i++)
  16509. X    memcpy (s + j, words [index + i], strlen (words [index + i])),
  16510. X    j += strlen (words [index + i]) + 1;
  16511. X  return nbytes;
  16512. X}
  16513. X
  16514. X/*
  16515. X  Skip over words in a string and return the address of the beginning of the
  16516. X  requested word, or NULL if the word is beyond the end of string.
  16517. X*/
  16518. X
  16519. Xchar *skip_to_word (char *s, int word)
  16520. X{
  16521. X  BOOLEAN quote;
  16522. X
  16523. X  while (*s != EOS && isspace (*s))    /* Skip to first word */
  16524. X    ++s;
  16525. X  while ((--word)) {
  16526. X    quote = FALSE;
  16527. X    while ((*s != EOS && !isspace (*s)) || (isspace (*s) && quote)) {
  16528. X      if (*s == '\"' || *s == '\'')
  16529. X    quote = !quote;
  16530. X      ++s;
  16531. X    }
  16532. X    while (*s != EOS && isspace (*s))
  16533. X      ++s;
  16534. X  }
  16535. X  if (*s == EOS)
  16536. X    return NULL;
  16537. X  return s;
  16538. X}
  16539. X
  16540. X/*
  16541. X  Some UNIXes do not provide strdup().
  16542. X*/
  16543. X
  16544. Xchar *mystrdup (char *s)
  16545. X{
  16546. X  char *r;
  16547. X
  16548. X  r = (char *) malloc ((strlen (s) + 1) * sizeof (char));
  16549. X  if (r)
  16550. X    strcpy (r, s);
  16551. X  return r;
  16552. X}
  16553. X
  16554. X#ifdef NEED_VSPRINTF
  16555. Xint vsprintf (dest, pat, args)
  16556. Xchar *dest, *pat, *args;
  16557. X{
  16558. X    FILE fakebuf;
  16559. X
  16560. X    fakebuf._ptr = dest;
  16561. X    fakebuf._cnt = 32767;
  16562. X#ifndef _IOSTRG
  16563. X#define _IOSTRG 0
  16564. X#endif
  16565. X    fakebuf._flag = _IOWRT|_IOSTRG;
  16566. X    _doprnt(pat, args, &fakebuf);
  16567. X    putc('\0', &fakebuf);
  16568. X    return 0;
  16569. X}
  16570. X#endif
  16571. *-*-END-of-src/misc.c-*-*
  16572. echo x - src/pqueue.c
  16573. sed 's/^X//' >src/pqueue.c <<'*-*-END-of-src/pqueue.c-*-*'
  16574. X/*
  16575. X  ----------------------------------------------------------------------------
  16576. X  |                    MAIL QUEUE PROCESSING ROUTINES                        |
  16577. X  |                                                                          |
  16578. X  |                             Version 1.1                                  |
  16579. X  |                                                                          |
  16580. X  |                (or, when Computer Science gets to you)                   |
  16581. X  |                                                                          |
  16582. X  |                    Written by Anastasios Kotsikonas                      |
  16583. X  |                           (tasos@cs.bu.edu)                              |
  16584. X  |                                                                          |
  16585. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  16586. X  | whole and not in parts, as long as you do not remove or alter the author |
  16587. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  16588. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  16589. X  | provided for your personal use, you may not alter the functions          |
  16590. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  16591. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  16592. X  | any changes you may have made. No part of the source code bearing a         |
  16593. X  | copyright notice can be included in commercial software systems without  |
  16594. X  | written permission by the author.                         |
  16595. X  | By using this software you are bound by this agreement.                  |
  16596. X  | This software comes with no warranties and cannot be sold for profit.    |
  16597. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  16598. X  | files when distributing this software.                                   |
  16599. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  16600. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  16601. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  16602. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  16603. X  | (ii).                                                                    |
  16604. X  ----------------------------------------------------------------------------
  16605. X
  16606. X  The 'system' mailmethod is used to attempt another delivery of the
  16607. X  specified files. If it cannot be done, the files are queued again.
  16608. X*/
  16609. X
  16610. X#include <stdio.h>
  16611. X#ifdef SYSLOG
  16612. X# ifdef ultrix
  16613. X#  include <sys/syslog.h>
  16614. X# else
  16615. X#  include <syslog.h>
  16616. X# endif
  16617. X#endif
  16618. X#ifndef unknown_port
  16619. X# ifndef __NeXT__
  16620. X#  include <unistd.h>
  16621. X# else
  16622. X#  include <libc.h>
  16623. X# endif
  16624. X#endif
  16625. X#include <sys/types.h>
  16626. X#include <sys/stat.h>
  16627. X#if !defined (sequent) && !defined (__NeXT__) && !defined (__convex__) && \
  16628. X !defined (apollo) && !defined (i386) && !defined (unknown_port)
  16629. X# include <sys/termio.h>
  16630. X#endif
  16631. X#ifndef sun
  16632. X# include <sys/ioctl.h>
  16633. X#endif
  16634. X#include <fcntl.h>
  16635. X#include <signal.h>
  16636. X#include <errno.h>
  16637. X#ifdef unknown_port
  16638. Xextern int errno;
  16639. X#endif
  16640. X#include "defs.h"
  16641. X#include "struct.h"
  16642. X#include "global.h"
  16643. X#include "pqueue.h"
  16644. X#if defined (__NeXT__) || defined (unknown_port)
  16645. X# include "next.h"
  16646. X#endif
  16647. X
  16648. X#ifdef __STDC__
  16649. Xextern char *tsprintf (char *, ...);
  16650. X#else
  16651. Xextern char *tsprintf ();
  16652. X#endif
  16653. Xextern int  _getopt (int, char **, char *);
  16654. Xextern void init_signals (void);
  16655. Xextern void catch_signals (void); 
  16656. Xextern void report_progress (FILE *, char *, int);
  16657. Xextern BOOLEAN sysmail (char *);
  16658. Xextern int  lock_file (char *, int, int, BOOLEAN);
  16659. Xextern void unlock_file (int);
  16660. Xextern int  otoi (char *);
  16661. X
  16662. Xvoid   main (int, char **, char **);
  16663. Xvoid   usage (void);
  16664. Xint    gexit (int);
  16665. X
  16666. Xvoid main (int argc, char **argv, char **envp)
  16667. X{
  16668. X  char *options = "eD", *mask;
  16669. X  int c, i, j;
  16670. X  FILE *f;
  16671. X  struct stat stat_buf;
  16672. X  extern int optind;
  16673. X  extern char *getenv();
  16674. X
  16675. X  prog = argv[0];
  16676. X  while ((c = _getopt (argc, argv, options)) != EOF)
  16677. X    switch ((char) c) {
  16678. X    case 'e': tty_echo = TRUE; break;
  16679. X    case 'D': debug = TRUE; break;
  16680. X    case '?':
  16681. X    default:
  16682. X      usage ();
  16683. X  }
  16684. X  if (optind == argc)
  16685. X    fprintf (stderr, "pqueue: filename(s) missing.\n"),
  16686. X    exit (3);
  16687. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  16688. X    umask (otoi (mask));
  16689. X  else
  16690. X    mask = "066",
  16691. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  16692. X#ifndef NO_LOCKS
  16693. X  if ((lfd = lock_file (PQUEUE_LOCK_FILE, O_RDWR, 0, FALSE)) < 0)
  16694. X    fprintf (stderr, "pqueue: Unable to lock %s. Aborting.\n",
  16695. X         PQUEUE_LOCK_FILE),
  16696. X    exit (1);
  16697. X#endif
  16698. X  init_signals();
  16699. X  catch_signals();
  16700. X
  16701. X  if (!tty_echo) {
  16702. X    j = -1;
  16703. X#if defined (TIOCNOTTY) && defined (SIGTTOU) && defined (SIGTTIN)
  16704. X    if ((i = open ("/dev/tty", 2)) >= 0)
  16705. X      j = ioctl (i, TIOCNOTTY, 0),
  16706. X      close (i);
  16707. X#endif
  16708. X    if (j < 0 && 
  16709. X#ifdef svr4
  16710. X    setsid ()
  16711. X#else
  16712. X# ifdef SETPGRP_NEEDS_ARGS
  16713. X    setpgrp (0, 0) 
  16714. X# else
  16715. X    setpgrp ()
  16716. X# endif
  16717. X#endif 
  16718. X    < 0)
  16719. X      report_progress (report, "WARNING: could not detach from tty", TRUE);
  16720. X  }
  16721. X
  16722. X#ifdef SYSLOG
  16723. X  openlog ("ListProcessor: pqueue", LOG_NDELAY
  16724. X# ifndef i386
  16725. X       |LOG_NOWAIT
  16726. X# endif
  16727. X       , SYSLOG);
  16728. X# ifndef ultrix
  16729. X  setlogmask (LOG_UPTO (LOG_INFO));
  16730. X# endif
  16731. X#else
  16732. X  if ((report = fopen (REPORT_PQUEUE, "a")) == NULL)
  16733. X    fprintf (stderr, "pqueue: Could not open %s\n", REPORT_PQUEUE),
  16734. X    exit (1);
  16735. X  chmod (REPORT_PQUEUE, 384);
  16736. X#endif
  16737. X  if ((f = fopen (PID_PQUEUE, "w")) != NULL)
  16738. X    fprintf (f, "%d", getpid()),
  16739. X    fclose (f);
  16740. X  signal (SIGINT, (void (*)()) gexit);
  16741. X  while (--argc >= optind) { /* main loop */
  16742. X    if (stat (argv [argc], &stat_buf))
  16743. X      report_progress (report, tsprintf ("\nmain(): Could not stat %s",
  16744. X                     argv [argc]), TRUE),
  16745. X      gexit (1);
  16746. X    if (sysmail (argv [argc]))
  16747. X      if (unlink (argv [argc]))
  16748. X     report_progress (report, tsprintf ("\nmain(): Could not unlink file %s",
  16749. X                       argv [argc]), TRUE),
  16750. X    gexit (1);
  16751. X  }
  16752. X#ifdef SYSLOG
  16753. X  closelog ();
  16754. X#else
  16755. X  fclose (report);
  16756. X#endif
  16757. X  gexit (0);
  16758. X}
  16759. X
  16760. Xvoid usage ()
  16761. X{
  16762. X  fprintf (stderr, "Usage: pqueue [-e] [-D] <files>\n\
  16763. X-e: Echo reports to the screen.\n\
  16764. X-D: Turn debug on.\n");
  16765. X  exit (3);
  16766. X}
  16767. X
  16768. X/*
  16769. X  Graceful exit. Remove pid file.
  16770. X*/
  16771. X
  16772. Xint gexit (int exitcode)
  16773. X{
  16774. X  unlink (PID_PQUEUE);
  16775. X#ifndef NO_LOCKS
  16776. X  unlock_file (lfd);
  16777. X#endif
  16778. X  exit (exitcode);
  16779. X}
  16780. *-*-END-of-src/pqueue.c-*-*
  16781. echo x - src/regerror.c
  16782. sed 's/^X//' >src/regerror.c <<'*-*-END-of-src/regerror.c-*-*'
  16783. X/*
  16784. X  Tasos Kotsikonas (8/20/92): Changed function so that it stores the error
  16785. X  message to a global variable.
  16786. X*/
  16787. X
  16788. X#include <stdio.h>
  16789. Xchar *regerr;
  16790. X
  16791. Xvoid
  16792. Xregerror(s)
  16793. Xchar *s;
  16794. X{
  16795. X  regerr = (char *) malloc ((strlen (s) + 1) * sizeof (char));
  16796. X  strcpy (regerr, s);
  16797. X}
  16798. *-*-END-of-src/regerror.c-*-*
  16799. echo x - src/regex.c
  16800. sed 's/^X//' >src/regex.c <<'*-*-END-of-src/regex.c-*-*'
  16801. X/*
  16802. X  ----------------------------------------------------------------------------
  16803. X  |                         REGULAR EXPRESSIONS                              |
  16804. X  |                                                                          |
  16805. X  |                             Version 1.0                                  |
  16806. X  |                                                                          |
  16807. X  |                (or, when Computer Science gets to you)                   |
  16808. X  |                                                                          |
  16809. X  |                    Written by Anastasios Kotsikonas                      |
  16810. X  |                           (tasos@cs.bu.edu)                              |
  16811. X  |                                                                          |
  16812. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  16813. X  | whole and not in parts, as long as you do not remove or alter the author |
  16814. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  16815. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  16816. X  | provided for your personal use, you may not alter the functions         |
  16817. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  16818. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  16819. X  | any changes you may have made. No part of the source code bearing a         |
  16820. X  | copyright notice can be included in commercial software systems without  |
  16821. X  | written permission by the author.                         |
  16822. X  | By using this software you are bound by this agreement.                  |
  16823. X  | This software comes with no warranties and cannot be sold for profit.    |
  16824. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  16825. X  | files when distributing this software.                                   |
  16826. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  16827. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  16828. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  16829. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  16830. X  | (ii).                                                                    |
  16831. X  ----------------------------------------------------------------------------
  16832. X
  16833. X  Author: Tasos Kotsikonas (tasos@cs.bu.edu)
  16834. X  Disclaimer: All proper disclaimers apply; these include death, damage of any
  16835. X          kind to anything and anyone, and this kind of legal garbage.
  16836. X  Copying: You may copy, alter and redistribute this software as you see fit,
  16837. X         but you may not sell it for profit.
  16838. X
  16839. X  Do pattern matching of two flavors: strict egrep(1), or extended egrep(1).
  16840. X  If the symbol egrep is #define'd below, strict egrep(1) syntax is used.
  16841. X
  16842. X  The main routine is re_strcmp() which takes a regular expression, a
  16843. X  string to match against, and a string specifying which of the matched
  16844. X  subparts are to be used to form a new string -- if this string is NULL no
  16845. X  such action is taken.
  16846. X
  16847. X  The new string is stored in the same space, so this string should be
  16848. X  long enough not to cause memory overwrites. To be able to do this match
  16849. X  substitution, the desired subparts of the regular expression should
  16850. X  be enclosed in ( and ). Each subpart is referenced to as \n where n is
  16851. X  a digit from 1 to 9.
  16852. X
  16853. X  For example, the following call:
  16854. X
  16855. X  strcpy (match, "\\2@\\1.UUCP");
  16856. X  re_strcmp ("[^!@]*!([^!@.]*)!([^!@]*)@.*", "GATE!HOP!USER@UUCP.SOME.COM",
  16857. X           match);
  16858. X
  16859. X  will return TRUE and store in 'match' "USER@HOP.UUCP". See the man page
  16860. X  for Henry Spencer's routines included for more information.
  16861. X
  16862. X  In extended mode, regular expressions may use the logical operators ~ (not),
  16863. X  & (and) and group expressions further with < and >. Because of the latter,
  16864. X  < and > may not be used in the ed(1) sense (\< is the default in the
  16865. X  context these routines were developed, and \> is useless in the same context).
  16866. X  To use any of these characters literally, precede them with a backslash (\).
  16867. X
  16868. X  For example:
  16869. X
  16870. X  re_strcmp ("~<.*\.COM|.*\.EDU>&~TASOS*", "TASOS@FOO.US", NULL)
  16871. X
  16872. X  will return FALSE.
  16873. X
  16874. X  re_strcmp() returns TRUE on success, FALSE if no match was found, or
  16875. X  -1 on error. In the latter case, the (char *) variable regerr contains the
  16876. X  actual error message.
  16877. X
  16878. X  The system uses modified pattern matching routines written by Henry Spencer
  16879. X  (Copyright (c) 1986 by University of Toronto) -- actually only regerror.c
  16880. X  was modified. Many thanks and kudos to Henry for this wonderful piece of code.
  16881. X
  16882. X  It is possible to use the ls(1) style wild characters * and ? by altering
  16883. X  the symbols STAR and QMARK below.
  16884. X
  16885. X  It is also possible to turn off ed(1) style pattern matching (i.e. turn
  16886. X  off the meaning of [ ] { } etc.) by using the function escape_re() where
  16887. X  marked with ###.
  16888. X
  16889. X  To test these routines compile with -Dtest and run independently as follows:
  16890. X
  16891. X        % cc -Dtest -I. regexp.c regsub.c regex.c regerror.c
  16892. X        % a.out 'regular-expression' file [match]
  16893. X
  16894. X  NOTICE: Spencer's $ matches the enf-of-line without mathing a newline
  16895. X  character. When compiling with -Dtest, $ is replaced with .$
  16896. X*/
  16897. X
  16898. X#include <stdio.h>
  16899. X#include <sys/types.h>
  16900. X#include <string.h>
  16901. X#include <ctype.h>
  16902. X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
  16903. X && !defined (sequent) && !defined (unknown_port)
  16904. X# include <malloc.h>
  16905. X#endif
  16906. X#include "regexp.h"
  16907. X
  16908. X/*
  16909. X#define egrep    Define it if you want to use strict egrep(1) regular expressions
  16910. X*/
  16911. X
  16912. X#define MAXLENGTH    1024    /* Maximum length of each regular expression */
  16913. X#define EOS        '\0'
  16914. X
  16915. Xint  re_strcmp (char *, char *, char *);
  16916. Xvoid escape_re (char *);
  16917. Xint  prevch (char *, char *);
  16918. Xint  nextch (char *);
  16919. X
  16920. X#ifdef test
  16921. Xint  main (int, char **);
  16922. Xvoid workaround (char *);
  16923. X#else
  16924. Xextern void report_progress (FILE *, char *, int);
  16925. Xextern FILE *report;
  16926. X#endif
  16927. X#ifndef egrep
  16928. Xchar *convert_re (char *);
  16929. Xint  icp (int);
  16930. Xint  push (int);
  16931. Xint  pop (void);
  16932. Xint  do_op (int, int, int);
  16933. Xvoid pop_op (void);
  16934. Xint  new_op (int);
  16935. Xint  eval (void);
  16936. Xint  isop (char *, char *);
  16937. X
  16938. X# define STAR        "*"    /* If ".*" then the meaning is that of ls(1) */
  16939. X# define QMARK        "?"    /* If "." then the meaning is that of ls(1) */
  16940. X# define LGROUPCH    '<'    /* Avoid ( and ) */
  16941. X# define RGROUPCH    '>'
  16942. X# define OR        1    /* Operators should be > 0 */
  16943. X# define AND        2
  16944. X# define NOT        3
  16945. X# define LPAREN        4
  16946. X# define RPAREN        5
  16947. X
  16948. Xtypedef struct _operator_stack {
  16949. X  int op;
  16950. X  int isp;    /* In-stack priority */
  16951. X  struct _operator_stack *next, *prev;
  16952. X} OPERATOR_STACK;
  16953. X
  16954. Xtypedef struct _operand_stack {
  16955. X  int val;
  16956. X  struct _operand_stack *next, *prev;
  16957. X} OPERAND_STACK;
  16958. X
  16959. XOPERATOR_STACK *op_top;
  16960. XOPERAND_STACK *val_top;
  16961. X#endif
  16962. X
  16963. Xint pliteral, literal, nliteral;
  16964. X
  16965. Xextern char *regerr;
  16966. X
  16967. X#ifdef test
  16968. Xint main (int argc, char **argv)
  16969. X{
  16970. X  FILE *f;
  16971. X  char s [1024], matches [1024];
  16972. X  int match;
  16973. X
  16974. X  if (argc < 3)
  16975. X    printf ("Usage: %s 'regular-expression' file [match]\n", argv[0]), exit (1);
  16976. X  if ((f = fopen (argv[2], "r")) == NULL)
  16977. X    printf ("%s: ", argv[2]), fflush (stdout), perror (""), exit (1);
  16978. X  while (!feof (f)) {
  16979. X    memset (s, EOS, sizeof (s));
  16980. X    fgets (s, sizeof (s) - 1, f);
  16981. X    if (argc > 3)
  16982. X      strcpy (matches, argv[3]);
  16983. X    if ((match = re_strcmp (argv[1], s, matches)) > 0)
  16984. X      printf ("MATCHES:%s\n", matches),
  16985. X      printf ("%s", s);
  16986. X    else if (match < 0)
  16987. X      printf ("Error in regular expression\n"),
  16988. X      exit (1);
  16989. X  }
  16990. X  fclose (f);
  16991. X  exit (0);
  16992. X}
  16993. X#endif
  16994. X
  16995. X/*
  16996. X  Check 'subject' againt the 'regexpr'. Return 1 on match, 0 if no match,
  16997. X  or -1 on error. To negegate a regular expression precede it with '~';
  16998. X  multiple regular expressions are separated by '|' or '&' (logical OR and
  16999. X  AND) and may be grouped with LGROUPCH and RGROUPCH. To escape the key
  17000. X  characters LGROUPCH * ? | & RGROUPCH use \.
  17001. X*/
  17002. X
  17003. Xint re_strcmp (char *regexpr, char *subject, char *result)
  17004. X{
  17005. X  char *re, *readdr, *s, _re[MAXLENGTH], matches [1024], *error;
  17006. X  int op, i;
  17007. X  regexp *cmp;
  17008. X
  17009. X  s = (char *) malloc ((strlen (regexpr) + 1) * sizeof (char));
  17010. X  strcpy (s, regexpr);
  17011. X#ifdef test
  17012. X  workaround (s);    /* Work around bugs with Spencer's code */
  17013. X#endif
  17014. X#ifndef egrep
  17015. X/*###        Do not escape ed(1) special characters.
  17016. X  escape_re (s);
  17017. X*/
  17018. X  readdr = re = convert_re (s);
  17019. X#else
  17020. X  re = s;
  17021. X#endif
  17022. X  do {
  17023. X#ifndef egrep
  17024. X    if ((op = isop (re, readdr))) {
  17025. X      if (new_op (op)) {
  17026. X    eval ();    /* Empty stacks */
  17027. X    return -1;
  17028. X      }
  17029. X      ++re;
  17030. X    }
  17031. X    else 
  17032. X#endif
  17033. X    {
  17034. X      i = 0;
  17035. X      while (*re != EOS && i < MAXLENGTH
  17036. X#ifndef egrep
  17037. X         && !isop (re, readdr)
  17038. X#endif
  17039. X        )
  17040. X    _re [i++] = *re,
  17041. X    ++re;
  17042. X      if (i == MAXLENGTH)    /* Overflow */
  17043. X    return -1;
  17044. X      _re [i] = EOS;
  17045. X      if (! (cmp = (regexp *) regcomp (_re))) {
  17046. X#ifndef test
  17047. X    error = (char *) malloc ((strlen (regerr) + strlen (_re) + 7) * 
  17048. X                 sizeof (char));
  17049. X    sprintf (error, "RE %s: %s\n", _re, regerr);
  17050. X    report_progress (report, error, 1);
  17051. X#else
  17052. X        printf ("RE %s: %s\n", _re, regerr);
  17053. X#endif
  17054. X    free ((char *) regerr);
  17055. X    free ((char *) error);
  17056. X#ifndef egrep
  17057. X    eval ();    /* Empty stacks */
  17058. X    free ((char *) readdr);
  17059. X#endif
  17060. X        return -1;
  17061. X      }
  17062. X      if (regexec (cmp, subject)) {
  17063. X    if (result)
  17064. X      regsub (cmp, result, matches),
  17065. X      strcpy (result, matches);
  17066. X    free ((regexp *) cmp);
  17067. X#ifndef egrep
  17068. X    push (1);
  17069. X#else
  17070. X    free ((char *) s);
  17071. X    return 1;
  17072. X#endif
  17073. X      }
  17074. X      else {
  17075. X    free ((regexp *) cmp);
  17076. X#ifndef egrep
  17077. X    push (0);
  17078. X#else
  17079. X    free ((char *) s);
  17080. X    return 0;
  17081. X#endif
  17082. X      }
  17083. X    }
  17084. X  } while (*re != EOS);
  17085. X#ifndef egrep
  17086. X  free ((char *) readdr);
  17087. X  free ((char *) s);
  17088. X  return eval ();
  17089. X#endif
  17090. X}
  17091. X
  17092. X/*
  17093. X  Scan 's' and escape the following characters: [ ] < > { } , ; . ^ $ + -
  17094. X  for regular expression matching.
  17095. X
  17096. X  To be used if one does not want ed(1) style pattern matching. Currently, this
  17097. X  function is unused.
  17098. X*/
  17099. X
  17100. Xvoid escape_re (char *s)
  17101. X{
  17102. X  char *r;
  17103. X
  17104. X  while (*s != EOS) {
  17105. X    switch (*s) {
  17106. X    case '[': case ']': case '<': case '>': case '+': case '-':
  17107. X    case ';': case ',': case '.': case '^': case '$': case '{': case '}':
  17108. X      r = s + strlen (s);       /* Start from the end */
  17109. X      while (r != s)
  17110. X        *(r + 1) = *r,
  17111. X        --r;
  17112. X      *(r + 1) = *r;
  17113. X      *r = '\\';
  17114. X      ++s;
  17115. X      break;
  17116. X    }
  17117. X    ++s;
  17118. X  }
  17119. X}
  17120. X
  17121. X/*
  17122. X  Possibly convert the wild characters * and ? to ed(1) regular expressions.
  17123. X  Handle escaped characters.
  17124. X*/
  17125. X
  17126. X#ifndef egrep
  17127. Xchar *convert_re (char *re)
  17128. X{
  17129. X  char *r, *b = re;
  17130. X  int i = 0;
  17131. X
  17132. X  if (! (r = (char *) malloc (sizeof (char))))
  17133. X# ifndef test
  17134. X    report_progress (report, "\nconvert_re(): malloc() failed", 1),
  17135. X    exit (11);
  17136. X# else
  17137. X    fprintf (stderr, "convert_re(): malloc() failed\n"),
  17138. X    exit (11);
  17139. X# endif
  17140. X  while (*re != EOS) {
  17141. X    prevch (re, b);    /* See if *re is literal */
  17142. X    switch (*re) {
  17143. X    case '\\':
  17144. X      if (re != b && literal) {
  17145. X    if (! (r = (char *) realloc (r, (i + 2) * sizeof (char))))
  17146. X# ifndef test
  17147. X      report_progress (report, "\nconvert_re(): realloc() failed", 1),
  17148. X      exit (11);
  17149. X# else
  17150. X      fprintf (stderr, "convert_re(): realloc() failed\n"),
  17151. X      exit (11);
  17152. X# endif
  17153. X    strncpy (r + i, "\\\\", 2);
  17154. X    i += 2;
  17155. X      }
  17156. X      break;
  17157. X    case '?':        /* Match one character */
  17158. X      if (re != b && literal) {    /* Literal */
  17159. X    if (! (r = (char *) realloc (r, (i + 1) * sizeof (char))))
  17160. X# ifndef test
  17161. X      report_progress (report, "\nconvert_re(): realloc() failed", 1),
  17162. X      exit (11);
  17163. X# else
  17164. X      fprintf (stderr, "convert_re(): realloc() failed\n"),
  17165. X      exit (11);
  17166. X# endif
  17167. X    *(r + i) = *re;
  17168. X    ++i;
  17169. X      }
  17170. X      else {
  17171. X    if (! (r = (char *) realloc (r, (i + strlen (QMARK)) * sizeof (char))))
  17172. X# ifndef test
  17173. X      report_progress (report, "\nconvert_re(): realloc() failed", 1),
  17174. X      exit (11);
  17175. X# else
  17176. X      fprintf (stderr, "convert_re(): realloc() failed\n"),
  17177. X      exit (11);
  17178. X# endif
  17179. X    strncpy (r + i, QMARK, strlen (QMARK));
  17180. X    i += strlen (QMARK);
  17181. X      }
  17182. X      break;
  17183. X    case '*':        /* Match multiple characters */
  17184. X      if (re != b && literal) {    /* Literal */
  17185. X    if (! (r = (char *) realloc (r, (i + 2) * sizeof (char))))
  17186. X# ifndef test
  17187. X      report_progress (report, "\nconvert_re(): realloc() failed", 1),
  17188. X      exit (11);
  17189. X# else
  17190. X      fprintf (stderr, "convert_re(): realloc() failed\n"),
  17191. X      exit (11);
  17192. X# endif
  17193. X    strncpy (r + i, "\\*", 2);
  17194. X    i += 2;
  17195. X      }
  17196. X      else {
  17197. X    if (! (r = (char *) realloc (r, (i + strlen (STAR)) * sizeof (char))))
  17198. X# ifndef test
  17199. X      report_progress (report, "\nconvert_re(): realloc() failed", 1),
  17200. X      exit (11);
  17201. X# else
  17202. X      fprintf (stderr, "convert_re(): realloc() failed\n"),
  17203. X      exit (11);
  17204. X# endif
  17205. X    strncpy (r + i, STAR, strlen (STAR));
  17206. X    i += strlen (STAR);
  17207. X      }
  17208. X      break;
  17209. X    default:
  17210. X      if (re != b && literal) {    /* carry over */
  17211. X    if (! (r = (char *) realloc (r, (i + 2) * sizeof (char))))
  17212. X# ifndef test
  17213. X      report_progress (report, "\nconvert_re(): realloc() failed", 1),
  17214. X      exit (11);
  17215. X# else
  17216. X      fprintf (stderr, "convert_re(): realloc() failed\n"),
  17217. X      exit (11);
  17218. X# endif
  17219. X    *(r + i) = *(re - 1);
  17220. X    *(r + i + 1) = *re;
  17221. X    i += 2;
  17222. X      }
  17223. X      else {
  17224. X    if (! (r = (char *) realloc (r, (i + 1) * sizeof (char))))
  17225. X# ifndef test
  17226. X      report_progress (report, "\nconvert_re(): realloc() failed", 1),
  17227. X      exit (11);
  17228. X# else
  17229. X      fprintf (stderr, "convert_re(): realloc() failed\n"),
  17230. X      exit (11);
  17231. X# endif
  17232. X    *(r + i) = *re;
  17233. X    ++i;
  17234. X      }
  17235. X    }
  17236. X    ++re;
  17237. X  }
  17238. X  if (! (r = (char *) realloc (r, (i + 1) * sizeof (char))))
  17239. X# ifndef test
  17240. X    report_progress (report, "\nconvert_re(): realloc() failed", 1),
  17241. X    exit (11);
  17242. X# else
  17243. X    fprintf (stderr, "convert_re(): realloc() failed\n"),
  17244. X    exit (11);
  17245. X# endif
  17246. X  *(r + i) = EOS;
  17247. X  return r;
  17248. X}
  17249. X
  17250. X/*
  17251. X  Return the in-coming priority of an operator.
  17252. X*/
  17253. X
  17254. Xint icp (int op)
  17255. X{
  17256. X  if (op == OR || op == AND) return 1;
  17257. X  if (op == LPAREN || op == NOT) return 4;
  17258. X  return 0;
  17259. X}
  17260. X
  17261. X/*
  17262. X  Push a new operand onto OPERAND_STACK.
  17263. X*/
  17264. X
  17265. Xint push (int val)
  17266. X{
  17267. X  OPERAND_STACK *s;
  17268. X
  17269. X  if (! (s = (OPERAND_STACK *) malloc (sizeof (OPERAND_STACK))))
  17270. X# ifndef test
  17271. X    report_progress (report, "\npush(): malloc() failed", 1),
  17272. X    exit (11);
  17273. X# else
  17274. X    fprintf (stderr, "push(): malloc() failed\n"),
  17275. X    exit (11);
  17276. X# endif
  17277. X  s->val = val;
  17278. X  s->prev = val_top;
  17279. X  s->next = NULL;
  17280. X  if (val_top)
  17281. X    val_top->next = s;
  17282. X  val_top = s;
  17283. X  return val;
  17284. X}
  17285. X
  17286. X/*
  17287. X  Pop an operand from OPERAND_STACK. Return 0 or 1, or -1 on error.
  17288. X*/
  17289. X
  17290. Xint pop ()
  17291. X{
  17292. X  int val;
  17293. X
  17294. X  if (!val_top)    /* Empty stack */
  17295. X    return -1;
  17296. X  val = val_top->val;
  17297. X  if (val_top->prev)
  17298. X    val_top = val_top->prev,
  17299. X    free ((OPERAND_STACK *) val_top->next),
  17300. X    val_top->next = NULL;
  17301. X  else
  17302. X    free ((OPERAND_STACK *) val_top),
  17303. X    val_top = NULL;
  17304. X  return val;
  17305. X}
  17306. X
  17307. X/*
  17308. X  Perform a boolean operation and return the result, or -1 on error.
  17309. X*/
  17310. X
  17311. Xint do_op (int op, int val1, int val2)
  17312. X{
  17313. X  if (val1 < 0 || val2 < 0)
  17314. X    return -1;
  17315. X  if (op == OR)
  17316. X    return val1 | val2;
  17317. X  if (op == AND)
  17318. X    return val1 & val2;
  17319. X  return !val1;
  17320. X}
  17321. X
  17322. X/*
  17323. X  Pop an operator. An operator will always be present.
  17324. X*/
  17325. X
  17326. Xvoid pop_op ()
  17327. X{
  17328. X  OPERATOR_STACK *s;
  17329. X
  17330. X  s = op_top;
  17331. X  op_top = op_top->prev;
  17332. X  if (op_top)
  17333. X    op_top->next = NULL;
  17334. X  free ((OPERATOR_STACK *) s);
  17335. X}
  17336. X
  17337. X/*
  17338. X  Process a new operator: push it anyway, or push it after popping other
  17339. X  operators with higher priority. Return -1 on error condition.
  17340. X*/
  17341. X
  17342. Xint new_op (int op)
  17343. X{
  17344. X  OPERATOR_STACK *s;
  17345. X  int res;
  17346. X
  17347. X  if (op < OR)
  17348. X    return -1;
  17349. X  if (op == RPAREN) {
  17350. X    do {    /* Pop and process operators till LPAREN */
  17351. X      if (!op_top)
  17352. X    return -1;
  17353. X      if (op_top->op != LPAREN) {
  17354. X    if (op_top->op == OR || op_top->op == AND)
  17355. X      res = push (do_op (op_top->op, pop (), pop ()));
  17356. X    else    /* NOT */
  17357. X      res = push (do_op (op_top->op, pop (), 0));
  17358. X    if (res < 0)    /* Error with operands */
  17359. X      return res;
  17360. X    pop_op ();    /* Pop processed operator */
  17361. X    if (!op_top)
  17362. X      return -1;
  17363. X      }
  17364. X    } while (op_top->op != LPAREN);
  17365. X    pop_op ();    /* LPAREN */
  17366. X  }
  17367. X  else {    /* Push new operator */
  17368. X    while (op_top && op_top->isp >= icp (op)) {    /* Process op w/ > priority */
  17369. X      if (op_top->op == OR || op_top->op == AND)
  17370. X    res = push (do_op (op_top->op, pop (), pop ()));
  17371. X      else    /* NOT */
  17372. X    res = push (do_op (op_top->op, pop (), 0));
  17373. X      if (res < 0)
  17374. X    return res;
  17375. X      pop_op ();
  17376. X    }
  17377. X    if (! (s = (OPERATOR_STACK *) malloc (sizeof (OPERATOR_STACK))))
  17378. X# ifndef test
  17379. X      report_progress (report, "\nnew_op(): malloc() failed", 1),
  17380. X      exit (11);
  17381. X# else
  17382. X      fprintf (stderr, "new_op(): malloc() failed\n"),
  17383. X      exit (11);
  17384. X# endif
  17385. X    s->op = op;
  17386. X    if (op == OR) s->isp = 1;
  17387. X    else if (op == AND) s->isp = 1;
  17388. X    else if (op == NOT) s->isp = 2;
  17389. X    else s->isp = 0;
  17390. X    s->prev = op_top;
  17391. X    s->next = NULL;
  17392. X    if (op_top)
  17393. X      op_top->next = s;
  17394. X    op_top = s;
  17395. X  }
  17396. X  return 0;
  17397. X}
  17398. X
  17399. X/*
  17400. X  Process the remaining operators and values. Return -1 on error.
  17401. X*/
  17402. X
  17403. Xint eval ()
  17404. X{
  17405. X  OPERATOR_STACK *op;
  17406. X  int res;
  17407. X
  17408. X  if (!op_top && !val_top)
  17409. X    return 0;
  17410. X  while (op_top) {
  17411. X    if (op_top->op != AND && op_top->op != OR && op_top->op != NOT) {
  17412. X      if (op_top->op < OR || op_top->op > RPAREN)
  17413. X# ifndef test
  17414. X    report_progress (report, "Internal error: unexpected op", 1);
  17415. X# else
  17416. X    printf ("Internal error: unexpected op %d\n", op_top->op);
  17417. X# endif
  17418. X      return -1;
  17419. X    }
  17420. X    if (op_top->op == OR || op_top->op == AND)
  17421. X      res = push (do_op (op_top->op, pop (), pop ()));
  17422. X    else    /* NOT */
  17423. X      res = push (do_op (op_top->op, pop (), 0));
  17424. X    if (res < 0)
  17425. X      return res;
  17426. X    op = op_top;
  17427. X    op_top = op_top->prev;
  17428. X    free ((OPERATOR_STACK *) op);
  17429. X  }
  17430. X  if (!val_top) {
  17431. X# ifndef test
  17432. X    report_progress (report, "Internal error: empty operand stack", 1);
  17433. X# else
  17434. X    printf ("Internal error: empty operand stack\n");
  17435. X# endif
  17436. X    return -1;
  17437. X  }
  17438. X  return pop ();
  17439. X}
  17440. X
  17441. X/*
  17442. X  Return the operator id if indeed 's' points to an operator. Return -1
  17443. X  on error.
  17444. X*/
  17445. X
  17446. Xint isop (char *s, char *b)
  17447. X{
  17448. X  char pch, nch;
  17449. X
  17450. X  pch = prevch (s, b);
  17451. X  if (literal) return 0;
  17452. X  nch = nextch (s);
  17453. X  if (*s == LGROUPCH)
  17454. X    if ((pch == '|' || pch == '&' || pch == '~' || pch == LGROUPCH) &&
  17455. X    !pliteral && ((nch != '|' && nch != '&' && nch != EOS) || nliteral))
  17456. X      return LPAREN;
  17457. X    else
  17458. X      return -1;
  17459. X  if (*s == RGROUPCH)
  17460. X    if (((pch != '|' && pch != '&' && pch != '~') || pliteral) && !nliteral &&
  17461. X    (nch == RGROUPCH || nch == '&' || nch == '|' || nch == EOS))
  17462. X      return RPAREN;
  17463. X    else
  17464. X      return -1;
  17465. X  if (*s == '~')
  17466. X    if ((pch == LGROUPCH || pch == '|' || pch == '&' || pch == '~') &&
  17467. X    !pliteral &&
  17468. X    ((nch != '|' && nch != '&' && nch != RGROUPCH && nch != EOS) ||
  17469. X     nliteral))
  17470. X      return NOT;
  17471. X    else
  17472. X      return -1;
  17473. X  if (*s == '|' || *s == '&')
  17474. X    if (((pch != '~' && pch != '|' && pch != '&') || pliteral) &&
  17475. X    ((nch != '|' && nch != '&' && nch != RGROUPCH &&
  17476. X      nch != EOS) || nliteral))
  17477. X      return (*s == '|' ? OR : AND);
  17478. X    else
  17479. X      return -1;
  17480. X  return 0;
  17481. X}
  17482. X#endif
  17483. X
  17484. X/*
  17485. X  Return the previous character from the current position in the
  17486. X  string. Set 'pliteral' to 1 if that previous character is escaped with \ and
  17487. X  'literal' to 1 if the current character is escaped with \.
  17488. X  In the comments, ^ means "beginning of the string", ? matches any character
  17489. X  except \, * matches absolutely any character and x is the current position.
  17490. X*/
  17491. X
  17492. Xint prevch (char *s, char *b)
  17493. X{
  17494. X  return
  17495. X    ((s) <= (b) ? 
  17496. X     (pliteral = literal = 0, *(s)) : /* ^x */
  17497. X     (((s) - 1) == (b) ? 
  17498. X      (*((s) - 1) == '\\' ? (pliteral = !(literal = 1), *((s) - 1)) /* ^\x */
  17499. X       : (pliteral = literal = 0, *((s) - 1))) /* ^?x */
  17500. X      : (*(s) == '\\' ? 
  17501. X     (*((s) - 2) == '\\' ? (pliteral = !(literal = 0), *((s) - 1)) /* \*\ */
  17502. X      : (*((s) - 1) == '\\' ? (pliteral = !(literal = 1), *((s) - 2)) /* ?\\ */
  17503. X         : (pliteral = literal = 0, *((s) - 1)))) /* ??\ */
  17504. X     : (*((s) - 1) == '\\' ? 
  17505. X        (*((s) - 2) == '\\' ? 
  17506. X         (((s) - 2) == (b) ? (pliteral = !(literal = 0), *((s) - 1)) /* ^\\x */
  17507. X          : (*((s) - 3) == '\\' ? (pliteral = literal = 1,*((s) - 2)) /* \\\x */
  17508. X         : (pliteral = !(literal = 0), *((s) - 1)))) /* ?\\x */
  17509. X         : (((s) - 2) == (b) ? (pliteral = !(literal = 1),*((s) - 2)) /* ^?\x */
  17510. X        : (*((s) - 3) == '\\' ? (pliteral = literal = 1, *((s) - 2)) /* \?\x */
  17511. X           : (pliteral = !(literal = 1),  *((s) - 2))))) /* ??\x */
  17512. X        : (*((s) - 2) == '\\' ? (pliteral = !(literal = 0),*((s) - 1)) /* \?x */
  17513. X           : (pliteral = literal = 0, *((s) - 1))))))); /* ??x */
  17514. X}
  17515. X
  17516. X/*
  17517. X  Return the next character from the current position. The current character
  17518. X  is guarranteed not to be a literal. In the comments below * matches
  17519. X  absolutely any character, ? matches anything but EOS, $ is the EOS and
  17520. X  x marks the current position. Also set 'nliteral' to 1 if the next character
  17521. X  is escaped with \.
  17522. X*/
  17523. X
  17524. Xint nextch (char *s)
  17525. X{
  17526. X  return
  17527. X    (*((s) + 1) == EOS ? (nliteral = 0, EOS) /* x$ */
  17528. X     : (*((s) + 1) == '\\' ? 
  17529. X    (*((s) + 2) == EOS ? (nliteral = 0, *((s) + 1)) /* x\$ */
  17530. X     : (nliteral = 1, *((s) + 2))) /* x\? */
  17531. X    : (nliteral = 0, *((s) + 1)))); /* x* */
  17532. X}
  17533. X#ifdef test
  17534. X
  17535. X/*
  17536. X  Henry Spencer's code requires that $ be converted to .$
  17537. X*/
  17538. X
  17539. Xvoid workaround (char *s)
  17540. X{
  17541. X  char *r, *b = s;
  17542. X
  17543. X  while (*s != EOS) {
  17544. X    switch (*s) {
  17545. X    case '$':
  17546. X      prevch (s, b);    /* See if thi char is a literal */
  17547. X      if (literal) {
  17548. X    ++s;
  17549. X    continue;
  17550. X      }
  17551. X      r = s + strlen (s);       /* Start from the end */
  17552. X      while (r != s)
  17553. X        *(r + 1) = *r,
  17554. X        --r;
  17555. X      *(r + 1) = *r;
  17556. X      *r = '.';
  17557. X      ++s;
  17558. X      break;
  17559. X    }
  17560. X    ++s;
  17561. X  }
  17562. X}
  17563. X#endif
  17564. *-*-END-of-src/regex.c-*-*
  17565. echo x - src/regexp.c
  17566. sed 's/^X//' >src/regexp.c <<'*-*-END-of-src/regexp.c-*-*'
  17567. X/*
  17568. X * regcomp and regexec -- regsub and regerror are elsewhere
  17569. X *
  17570. X *    Copyright (c) 1986 by University of Toronto.
  17571. X *    Written by Henry Spencer.  Not derived from licensed software.
  17572. X *
  17573. X *    Permission is granted to anyone to use this software for any
  17574. X *    purpose on any computer system, and to redistribute it freely,
  17575. X *    subject to the following restrictions:
  17576. X *
  17577. X *    1. The author is not responsible for the consequences of use of
  17578. X *        this software, no matter how awful, even if they arise
  17579. X *        from defects in it.
  17580. X *
  17581. X *    2. The origin of this software must not be misrepresented, either
  17582. X *        by explicit claim or by omission.
  17583. X *
  17584. X *    3. Altered versions must be plainly marked as such, and must not
  17585. X *        be misrepresented as being the original software.
  17586. X *
  17587. X * Beware that some of this code is subtly aware of the way operator
  17588. X * precedence is structured in regular expressions.  Serious changes in
  17589. X * regular-expression syntax might require a total rethink.
  17590. X */
  17591. X#include <stdio.h>
  17592. X#include "regexp.h"
  17593. X#include "regmagic.h"
  17594. X
  17595. X/*
  17596. X * The "internal use only" fields in regexp.h are present to pass info from
  17597. X * compile to execute that permits the execute phase to run lots faster on
  17598. X * simple cases.  They are:
  17599. X *
  17600. X * regstart    char that must begin a match; '\0' if none obvious
  17601. X * reganch    is the match anchored (at beginning-of-line only)?
  17602. X * regmust    string (pointer into program) that match must include, or NULL
  17603. X * regmlen    length of regmust string
  17604. X *
  17605. X * Regstart and reganch permit very fast decisions on suitable starting points
  17606. X * for a match, cutting down the work a lot.  Regmust permits fast rejection
  17607. X * of lines that cannot possibly match.  The regmust tests are costly enough
  17608. X * that regcomp() supplies a regmust only if the r.e. contains something
  17609. X * potentially expensive (at present, the only such thing detected is * or +
  17610. X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  17611. X * supplied because the test in regexec() needs it and regcomp() is computing
  17612. X * it anyway.
  17613. X */
  17614. X
  17615. X/*
  17616. X * Structure for regexp "program".  This is essentially a linear encoding
  17617. X * of a nondeterministic finite-state machine (aka syntax charts or
  17618. X * "railroad normal form" in parsing technology).  Each node is an opcode
  17619. X * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  17620. X * all nodes except BRANCH implement concatenation; a "next" pointer with
  17621. X * a BRANCH on both ends of it is connecting two alternatives.  (Here we
  17622. X * have one of the subtle syntax dependencies:  an individual BRANCH (as
  17623. X * opposed to a collection of them) is never concatenated with anything
  17624. X * because of operator precedence.)  The operand of some types of node is
  17625. X * a literal string; for others, it is a node leading into a sub-FSM.  In
  17626. X * particular, the operand of a BRANCH node is the first node of the branch.
  17627. X * (NB this is *not* a tree structure:  the tail of the branch connects
  17628. X * to the thing following the set of BRANCHes.)  The opcodes are:
  17629. X */
  17630. X
  17631. X/* definition    number    opnd?    meaning */
  17632. X#define    END    0    /* no    End of program. */
  17633. X#define    BOL    1    /* no    Match "" at beginning of line. */
  17634. X#define    EOL    2    /* no    Match "" at end of line. */
  17635. X#define    ANY    3    /* no    Match any one character. */
  17636. X#define    ANYOF    4    /* str    Match any character in this string. */
  17637. X#define    ANYBUT    5    /* str    Match any character not in this string. */
  17638. X#define    BRANCH    6    /* node    Match this alternative, or the next... */
  17639. X#define    BACK    7    /* no    Match "", "next" ptr points backward. */
  17640. X#define    EXACTLY    8    /* str    Match this string. */
  17641. X#define    NOTHING    9    /* no    Match empty string. */
  17642. X#define    STAR    10    /* node    Match this (simple) thing 0 or more times. */
  17643. X#define    PLUS    11    /* node    Match this (simple) thing 1 or more times. */
  17644. X#define    OPEN    20    /* no    Mark this point in input as start of #n. */
  17645. X            /*    OPEN+1 is number 1, etc. */
  17646. X#define    CLOSE    30    /* no    Analogous to OPEN. */
  17647. X
  17648. X/*
  17649. X * Opcode notes:
  17650. X *
  17651. X * BRANCH    The set of branches constituting a single choice are hooked
  17652. X *        together with their "next" pointers, since precedence prevents
  17653. X *        anything being concatenated to any individual branch.  The
  17654. X *        "next" pointer of the last BRANCH in a choice points to the
  17655. X *        thing following the whole choice.  This is also where the
  17656. X *        final "next" pointer of each individual branch points; each
  17657. X *        branch starts with the operand node of a BRANCH node.
  17658. X *
  17659. X * BACK        Normal "next" pointers all implicitly point forward; BACK
  17660. X *        exists to make loop structures possible.
  17661. X *
  17662. X * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
  17663. X *        BRANCH structures using BACK.  Simple cases (one character
  17664. X *        per match) are implemented with STAR and PLUS for speed
  17665. X *        and to minimize recursive plunges.
  17666. X *
  17667. X * OPEN,CLOSE    ...are numbered at compile time.
  17668. X */
  17669. X
  17670. X/*
  17671. X * A node is one char of opcode followed by two chars of "next" pointer.
  17672. X * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  17673. X * value is a positive offset from the opcode of the node containing it.
  17674. X * An operand, if any, simply follows the node.  (Note that much of the
  17675. X * code generation knows about this implicit relationship.)
  17676. X *
  17677. X * Using two bytes for the "next" pointer is vast overkill for most things,
  17678. X * but allows patterns to get big without disasters.
  17679. X */
  17680. X#define    OP(p)    (*(p))
  17681. X#define    NEXT(p)    (((*((p)+1)&0377)<<8) + *((p)+2)&0377)
  17682. X#define    OPERAND(p)    ((p) + 3)
  17683. X
  17684. X/*
  17685. X * See regmagic.h for one further detail of program structure.
  17686. X */
  17687. X
  17688. X
  17689. X/*
  17690. X * Utility definitions.
  17691. X */
  17692. X#ifndef CHARBITS
  17693. X#define    UCHARAT(p)    ((int)*(unsigned char *)(p))
  17694. X#else
  17695. X#define    UCHARAT(p)    ((int)*(p)&CHARBITS)
  17696. X#endif
  17697. X
  17698. X#define    FAIL(m)    { regerror(m); return(NULL); }
  17699. X#define    ISMULT(c)    ((c) == '*' || (c) == '+' || (c) == '?')
  17700. X#define    META    "^$.[()|?+*\\"
  17701. X
  17702. X/*
  17703. X * Flags to be passed up and down.
  17704. X */
  17705. X#define    HASWIDTH    01    /* Known never to match null string. */
  17706. X#define    SIMPLE        02    /* Simple enough to be STAR/PLUS operand. */
  17707. X#define    SPSTART        04    /* Starts with * or +. */
  17708. X#define    WORST        0    /* Worst case. */
  17709. X
  17710. X/*
  17711. X * Global work variables for regcomp().
  17712. X */
  17713. Xstatic char *regparse;        /* Input-scan pointer. */
  17714. Xstatic int regnpar;        /* () count. */
  17715. Xstatic char regdummy;
  17716. Xstatic char *regcode;        /* Code-emit pointer; ®dummy = don't. */
  17717. Xstatic long regsize;        /* Code size. */
  17718. X
  17719. X/*
  17720. X * Forward declarations for regcomp()'s friends.
  17721. X */
  17722. X#ifndef STATIC
  17723. X#define    STATIC    static
  17724. X#endif
  17725. XSTATIC char *reg();
  17726. XSTATIC char *regbranch();
  17727. XSTATIC char *regpiece();
  17728. XSTATIC char *regatom();
  17729. XSTATIC char *regnode();
  17730. XSTATIC char *regnext();
  17731. XSTATIC void regc();
  17732. XSTATIC void reginsert();
  17733. XSTATIC void regtail();
  17734. XSTATIC void regoptail();
  17735. X#ifdef STRCSPN
  17736. XSTATIC int strcspn();
  17737. X#endif
  17738. X
  17739. X/*
  17740. X - regcomp - compile a regular expression into internal code
  17741. X *
  17742. X * We can't allocate space until we know how big the compiled form will be,
  17743. X * but we can't compile it (and thus know how big it is) until we've got a
  17744. X * place to put the code.  So we cheat:  we compile it twice, once with code
  17745. X * generation turned off and size counting turned on, and once "for real".
  17746. X * This also means that we don't allocate space until we are sure that the
  17747. X * thing really will compile successfully, and we never have to move the
  17748. X * code and thus invalidate pointers into it.  (Note that it has to be in
  17749. X * one piece because free() must be able to free it all.)
  17750. X *
  17751. X * Beware that the optimization-preparation code in here knows about some
  17752. X * of the structure of the compiled regexp.
  17753. X */
  17754. Xregexp *
  17755. Xregcomp(exp)
  17756. Xchar *exp;
  17757. X{
  17758. X    register regexp *r;
  17759. X    register char *scan;
  17760. X    register char *longest;
  17761. X    register int len;
  17762. X    int flags;
  17763. X    extern char *malloc();
  17764. X
  17765. X    if (exp == NULL)
  17766. X        FAIL("NULL argument");
  17767. X
  17768. X    /* First pass: determine size, legality. */
  17769. X    regparse = exp;
  17770. X    regnpar = 1;
  17771. X    regsize = 0L;
  17772. X    regcode = ®dummy;
  17773. X    regc(MAGIC);
  17774. X    if (reg(0, &flags) == NULL)
  17775. X        return(NULL);
  17776. X
  17777. X    /* Small enough for pointer-storage convention? */
  17778. X    if (regsize >= 32767L)        /* Probably could be 65535L. */
  17779. X        FAIL("regexp too big");
  17780. X
  17781. X    /* Allocate space. */
  17782. X    r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
  17783. X    if (r == NULL)
  17784. X        FAIL("out of space");
  17785. X
  17786. X    /* Second pass: emit code. */
  17787. X    regparse = exp;
  17788. X    regnpar = 1;
  17789. X    regcode = r->program;
  17790. X    regc(MAGIC);
  17791. X    if (reg(0, &flags) == NULL)
  17792. X        return(NULL);
  17793. X
  17794. X    /* Dig out information for optimizations. */
  17795. X    r->regstart = '\0';    /* Worst-case defaults. */
  17796. X    r->reganch = 0;
  17797. X    r->regmust = NULL;
  17798. X    r->regmlen = 0;
  17799. X    scan = r->program+1;            /* First BRANCH. */
  17800. X    if (OP(regnext(scan)) == END) {        /* Only one top-level choice. */
  17801. X        scan = OPERAND(scan);
  17802. X
  17803. X        /* Starting-point info. */
  17804. X        if (OP(scan) == EXACTLY)
  17805. X            r->regstart = *OPERAND(scan);
  17806. X        else if (OP(scan) == BOL)
  17807. X            r->reganch++;
  17808. X
  17809. X        /*
  17810. X         * If there's something expensive in the r.e., find the
  17811. X         * longest literal string that must appear and make it the
  17812. X         * regmust.  Resolve ties in favor of later strings, since
  17813. X         * the regstart check works with the beginning of the r.e.
  17814. X         * and avoiding duplication strengthens checking.  Not a
  17815. X         * strong reason, but sufficient in the absence of others.
  17816. X         */
  17817. X        if (flags&SPSTART) {
  17818. X            longest = NULL;
  17819. X            len = 0;
  17820. X            for (; scan != NULL; scan = regnext(scan))
  17821. X                if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  17822. X                    longest = OPERAND(scan);
  17823. X                    len = strlen(OPERAND(scan));
  17824. X                }
  17825. X            r->regmust = longest;
  17826. X            r->regmlen = len;
  17827. X        }
  17828. X    }
  17829. X
  17830. X    return(r);
  17831. X}
  17832. X
  17833. X/*
  17834. X - reg - regular expression, i.e. main body or parenthesized thing
  17835. X *
  17836. X * Caller must absorb opening parenthesis.
  17837. X *
  17838. X * Combining parenthesis handling with the base level of regular expression
  17839. X * is a trifle forced, but the need to tie the tails of the branches to what
  17840. X * follows makes it hard to avoid.
  17841. X */
  17842. Xstatic char *
  17843. Xreg(paren, flagp)
  17844. Xint paren;            /* Parenthesized? */
  17845. Xint *flagp;
  17846. X{
  17847. X    register char *ret;
  17848. X    register char *br;
  17849. X    register char *ender;
  17850. X    register int parno;
  17851. X    int flags;
  17852. X
  17853. X    *flagp = HASWIDTH;    /* Tentatively. */
  17854. X
  17855. X    /* Make an OPEN node, if parenthesized. */
  17856. X    if (paren) {
  17857. X        if (regnpar >= NSUBEXP)
  17858. X            FAIL("too many ()");
  17859. X        parno = regnpar;
  17860. X        regnpar++;
  17861. X        ret = regnode(OPEN+parno);
  17862. X    } else
  17863. X        ret = NULL;
  17864. X
  17865. X    /* Pick up the branches, linking them together. */
  17866. X    br = regbranch(&flags);
  17867. X    if (br == NULL)
  17868. X        return(NULL);
  17869. X    if (ret != NULL)
  17870. X        regtail(ret, br);    /* OPEN -> first. */
  17871. X    else
  17872. X        ret = br;
  17873. X    if (!(flags&HASWIDTH))
  17874. X        *flagp &= ~HASWIDTH;
  17875. X    *flagp |= flags&SPSTART;
  17876. X    while (*regparse == '|') {
  17877. X        regparse++;
  17878. X        br = regbranch(&flags);
  17879. X        if (br == NULL)
  17880. X            return(NULL);
  17881. X        regtail(ret, br);    /* BRANCH -> BRANCH. */
  17882. X        if (!(flags&HASWIDTH))
  17883. X            *flagp &= ~HASWIDTH;
  17884. X        *flagp |= flags&SPSTART;
  17885. X    }
  17886. X
  17887. X    /* Make a closing node, and hook it on the end. */
  17888. X    ender = regnode((paren) ? CLOSE+parno : END);    
  17889. X    regtail(ret, ender);
  17890. X
  17891. X    /* Hook the tails of the branches to the closing node. */
  17892. X    for (br = ret; br != NULL; br = regnext(br))
  17893. X        regoptail(br, ender);
  17894. X
  17895. X    /* Check for proper termination. */
  17896. X    if (paren && *regparse++ != ')') {
  17897. X        FAIL("unmatched ()");
  17898. X    } else if (!paren && *regparse != '\0') {
  17899. X        if (*regparse == ')') {
  17900. X            FAIL("unmatched ()");
  17901. X        } else
  17902. X            FAIL("junk on end");    /* "Can't happen". */
  17903. X        /* NOTREACHED */
  17904. X    }
  17905. X
  17906. X    return(ret);
  17907. X}
  17908. X
  17909. X/*
  17910. X - regbranch - one alternative of an | operator
  17911. X *
  17912. X * Implements the concatenation operator.
  17913. X */
  17914. Xstatic char *
  17915. Xregbranch(flagp)
  17916. Xint *flagp;
  17917. X{
  17918. X    register char *ret;
  17919. X    register char *chain;
  17920. X    register char *latest;
  17921. X    int flags;
  17922. X
  17923. X    *flagp = WORST;        /* Tentatively. */
  17924. X
  17925. X    ret = regnode(BRANCH);
  17926. X    chain = NULL;
  17927. X    while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  17928. X        latest = regpiece(&flags);
  17929. X        if (latest == NULL)
  17930. X            return(NULL);
  17931. X        *flagp |= flags&HASWIDTH;
  17932. X        if (chain == NULL)    /* First piece. */
  17933. X            *flagp |= flags&SPSTART;
  17934. X        else
  17935. X            regtail(chain, latest);
  17936. X        chain = latest;
  17937. X    }
  17938. X    if (chain == NULL)    /* Loop ran zero times. */
  17939. X        (void) regnode(NOTHING);
  17940. X
  17941. X    return(ret);
  17942. X}
  17943. X
  17944. X/*
  17945. X - regpiece - something followed by possible [*+?]
  17946. X *
  17947. X * Note that the branching code sequences used for ? and the general cases
  17948. X * of * and + are somewhat optimized:  they use the same NOTHING node as
  17949. X * both the endmarker for their branch list and the body of the last branch.
  17950. X * It might seem that this node could be dispensed with entirely, but the
  17951. X * endmarker role is not redundant.
  17952. X */
  17953. Xstatic char *
  17954. Xregpiece(flagp)
  17955. Xint *flagp;
  17956. X{
  17957. X    register char *ret;
  17958. X    register char op;
  17959. X    register char *next;
  17960. X    int flags;
  17961. X
  17962. X    ret = regatom(&flags);
  17963. X    if (ret == NULL)
  17964. X        return(NULL);
  17965. X
  17966. X    op = *regparse;
  17967. X    if (!ISMULT(op)) {
  17968. X        *flagp = flags;
  17969. X        return(ret);
  17970. X    }
  17971. X
  17972. X    if (!(flags&HASWIDTH) && op != '?')
  17973. X        FAIL("*+ operand could be empty");
  17974. X    *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
  17975. X
  17976. X    if (op == '*' && (flags&SIMPLE))
  17977. X        reginsert(STAR, ret);
  17978. X    else if (op == '*') {
  17979. X        /* Emit x* as (x&|), where & means "self". */
  17980. X        reginsert(BRANCH, ret);            /* Either x */
  17981. X        regoptail(ret, regnode(BACK));        /* and loop */
  17982. X        regoptail(ret, ret);            /* back */
  17983. X        regtail(ret, regnode(BRANCH));        /* or */
  17984. X        regtail(ret, regnode(NOTHING));        /* null. */
  17985. X    } else if (op == '+' && (flags&SIMPLE))
  17986. X        reginsert(PLUS, ret);
  17987. X    else if (op == '+') {
  17988. X        /* Emit x+ as x(&|), where & means "self". */
  17989. X        next = regnode(BRANCH);            /* Either */
  17990. X        regtail(ret, next);
  17991. X        regtail(regnode(BACK), ret);        /* loop back */
  17992. X        regtail(next, regnode(BRANCH));        /* or */
  17993. X        regtail(ret, regnode(NOTHING));        /* null. */
  17994. X    } else if (op == '?') {
  17995. X        /* Emit x? as (x|) */
  17996. X        reginsert(BRANCH, ret);            /* Either x */
  17997. X        regtail(ret, regnode(BRANCH));        /* or */
  17998. X        next = regnode(NOTHING);        /* null. */
  17999. X        regtail(ret, next);
  18000. X        regoptail(ret, next);
  18001. X    }
  18002. X    regparse++;
  18003. X    if (ISMULT(*regparse))
  18004. X        FAIL("nested *?+");
  18005. X
  18006. X    return(ret);
  18007. X}
  18008. X
  18009. X/*
  18010. X - regatom - the lowest level
  18011. X *
  18012. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  18013. X * it can turn them into a single node, which is smaller to store and
  18014. X * faster to run.  Backslashed characters are exceptions, each becoming a
  18015. X * separate node; the code is simpler that way and it's not worth fixing.
  18016. X */
  18017. Xstatic char *
  18018. Xregatom(flagp)
  18019. Xint *flagp;
  18020. X{
  18021. X    register char *ret;
  18022. X    int flags;
  18023. X
  18024. X    *flagp = WORST;        /* Tentatively. */
  18025. X
  18026. X    switch (*regparse++) {
  18027. X    case '^':
  18028. X        ret = regnode(BOL);
  18029. X        break;
  18030. X    case '$':
  18031. X        ret = regnode(EOL);
  18032. X        break;
  18033. X    case '.':
  18034. X        ret = regnode(ANY);
  18035. X        *flagp |= HASWIDTH|SIMPLE;
  18036. X        break;
  18037. X    case '[': {
  18038. X            register int class;
  18039. X            register int classend;
  18040. X
  18041. X            if (*regparse == '^') {    /* Complement of range. */
  18042. X                ret = regnode(ANYBUT);
  18043. X                regparse++;
  18044. X            } else
  18045. X                ret = regnode(ANYOF);
  18046. X            if (*regparse == ']' || *regparse == '-')
  18047. X                regc(*regparse++);
  18048. X            while (*regparse != '\0' && *regparse != ']') {
  18049. X                if (*regparse == '-') {
  18050. X                    regparse++;
  18051. X                    if (*regparse == ']' || *regparse == '\0')
  18052. X                        regc('-');
  18053. X                    else {
  18054. X                        class = UCHARAT(regparse-2)+1;
  18055. X                        classend = UCHARAT(regparse);
  18056. X                        if (class > classend+1)
  18057. X                            FAIL("invalid [] range");
  18058. X                        for (; class <= classend; class++)
  18059. X                            regc(class);
  18060. X                        regparse++;
  18061. X                    }
  18062. X                } else
  18063. X                    regc(*regparse++);
  18064. X            }
  18065. X            regc('\0');
  18066. X            if (*regparse != ']')
  18067. X                FAIL("unmatched []");
  18068. X            regparse++;
  18069. X            *flagp |= HASWIDTH|SIMPLE;
  18070. X        }
  18071. X        break;
  18072. X    case '(':
  18073. X        ret = reg(1, &flags);
  18074. X        if (ret == NULL)
  18075. X            return(NULL);
  18076. X        *flagp |= flags&(HASWIDTH|SPSTART);
  18077. X        break;
  18078. X    case '\0':
  18079. X    case '|':
  18080. X    case ')':
  18081. X        FAIL("internal urp");    /* Supposed to be caught earlier. */
  18082. X        break;
  18083. X    case '?':
  18084. X    case '+':
  18085. X    case '*':
  18086. X        FAIL("?+* follows nothing");
  18087. X        break;
  18088. X    case '\\':
  18089. X        if (*regparse == '\0')
  18090. X            FAIL("trailing \\");
  18091. X        ret = regnode(EXACTLY);
  18092. X        regc(*regparse++);
  18093. X        regc('\0');
  18094. X        *flagp |= HASWIDTH|SIMPLE;
  18095. X        break;
  18096. X    default: {
  18097. X            register int len;
  18098. X            register char ender;
  18099. X
  18100. X            regparse--;
  18101. X            len = strcspn(regparse, META);
  18102. X            if (len <= 0)
  18103. X                FAIL("internal disaster");
  18104. X            ender = *(regparse+len);
  18105. X            if (len > 1 && ISMULT(ender))
  18106. X                len--;        /* Back off clear of ?+* operand. */
  18107. X            *flagp |= HASWIDTH;
  18108. X            if (len == 1)
  18109. X                *flagp |= SIMPLE;
  18110. X            ret = regnode(EXACTLY);
  18111. X            while (len > 0) {
  18112. X                regc(*regparse++);
  18113. X                len--;
  18114. X            }
  18115. X            regc('\0');
  18116. X        }
  18117. X        break;
  18118. X    }
  18119. X
  18120. X    return(ret);
  18121. X}
  18122. X
  18123. X/*
  18124. X - regnode - emit a node
  18125. X */
  18126. Xstatic char *            /* Location. */
  18127. Xregnode(op)
  18128. Xchar op;
  18129. X{
  18130. X    register char *ret;
  18131. X    register char *ptr;
  18132. X
  18133. X    ret = regcode;
  18134. X    if (ret == ®dummy) {
  18135. X        regsize += 3;
  18136. X        return(ret);
  18137. X    }
  18138. X
  18139. X    ptr = ret;
  18140. X    *ptr++ = op;
  18141. X    *ptr++ = '\0';        /* Null "next" pointer. */
  18142. X    *ptr++ = '\0';
  18143. X    regcode = ptr;
  18144. X
  18145. X    return(ret);
  18146. X}
  18147. X
  18148. X/*
  18149. X - regc - emit (if appropriate) a byte of code
  18150. X */
  18151. Xstatic void
  18152. Xregc(b)
  18153. Xchar b;
  18154. X{
  18155. X    if (regcode != ®dummy)
  18156. X        *regcode++ = b;
  18157. X    else
  18158. X        regsize++;
  18159. X}
  18160. X
  18161. X/*
  18162. X - reginsert - insert an operator in front of already-emitted operand
  18163. X *
  18164. X * Means relocating the operand.
  18165. X */
  18166. Xstatic void
  18167. Xreginsert(op, opnd)
  18168. Xchar op;
  18169. Xchar *opnd;
  18170. X{
  18171. X    register char *src;
  18172. X    register char *dst;
  18173. X    register char *place;
  18174. X
  18175. X    if (regcode == ®dummy) {
  18176. X        regsize += 3;
  18177. X        return;
  18178. X    }
  18179. X
  18180. X    src = regcode;
  18181. X    regcode += 3;
  18182. X    dst = regcode;
  18183. X    while (src > opnd)
  18184. X        *--dst = *--src;
  18185. X
  18186. X    place = opnd;        /* Op node, where operand used to be. */
  18187. X    *place++ = op;
  18188. X    *place++ = '\0';
  18189. X    *place++ = '\0';
  18190. X}
  18191. X
  18192. X/*
  18193. X - regtail - set the next-pointer at the end of a node chain
  18194. X */
  18195. Xstatic void
  18196. Xregtail(p, val)
  18197. Xchar *p;
  18198. Xchar *val;
  18199. X{
  18200. X    register char *scan;
  18201. X    register char *temp;
  18202. X    register int offset;
  18203. X
  18204. X    if (p == ®dummy)
  18205. X        return;
  18206. X
  18207. X    /* Find last node. */
  18208. X    scan = p;
  18209. X    for (;;) {
  18210. X        temp = regnext(scan);
  18211. X        if (temp == NULL)
  18212. X            break;
  18213. X        scan = temp;
  18214. X    }
  18215. X
  18216. X    if (OP(scan) == BACK)
  18217. X        offset = scan - val;
  18218. X    else
  18219. X        offset = val - scan;
  18220. X    *(scan+1) = (offset>>8)&0377;
  18221. X    *(scan+2) = offset&0377;
  18222. X}
  18223. X
  18224. X/*
  18225. X - regoptail - regtail on operand of first argument; nop if operandless
  18226. X */
  18227. Xstatic void
  18228. Xregoptail(p, val)
  18229. Xchar *p;
  18230. Xchar *val;
  18231. X{
  18232. X    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  18233. X    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  18234. X        return;
  18235. X    regtail(OPERAND(p), val);
  18236. X}
  18237. X
  18238. X/*
  18239. X * regexec and friends
  18240. X */
  18241. X
  18242. X/*
  18243. X * Global work variables for regexec().
  18244. X */
  18245. Xstatic char *reginput;        /* String-input pointer. */
  18246. Xstatic char *regbol;        /* Beginning of input, for ^ check. */
  18247. Xstatic char **regstartp;    /* Pointer to startp array. */
  18248. Xstatic char **regendp;        /* Ditto for endp. */
  18249. X
  18250. X/*
  18251. X * Forwards.
  18252. X */
  18253. XSTATIC int regtry();
  18254. XSTATIC int regmatch();
  18255. XSTATIC int regrepeat();
  18256. X
  18257. X#ifdef DEBUG
  18258. Xint regnarrate = 0;
  18259. Xvoid regdump();
  18260. XSTATIC char *regprop();
  18261. X#endif
  18262. X
  18263. X/*
  18264. X - regexec - match a regexp against a string
  18265. X */
  18266. Xint
  18267. Xregexec(prog, string)
  18268. Xregister regexp *prog;
  18269. Xregister char *string;
  18270. X{
  18271. X    register char *s;
  18272. X    extern char *strchr();
  18273. X
  18274. X    /* Be paranoid... */
  18275. X    if (prog == NULL || string == NULL) {
  18276. X        regerror("NULL parameter");
  18277. X        return(0);
  18278. X    }
  18279. X
  18280. X    /* Check validity of program. */
  18281. X    if (UCHARAT(prog->program) != MAGIC) {
  18282. X        regerror("corrupted program");
  18283. X        return(0);
  18284. X    }
  18285. X
  18286. X    /* If there is a "must appear" string, look for it. */
  18287. X    if (prog->regmust != NULL) {
  18288. X        s = string;
  18289. X        while ((s = strchr(s, prog->regmust[0])) != NULL) {
  18290. X            if (strncmp(s, prog->regmust, prog->regmlen) == 0)
  18291. X                break;    /* Found it. */
  18292. X            s++;
  18293. X        }
  18294. X        if (s == NULL)    /* Not present. */
  18295. X            return(0);
  18296. X    }
  18297. X
  18298. X    /* Mark beginning of line for ^ . */
  18299. X    regbol = string;
  18300. X
  18301. X    /* Simplest case:  anchored match need be tried only once. */
  18302. X    if (prog->reganch)
  18303. X        return(regtry(prog, string));
  18304. X
  18305. X    /* Messy cases:  unanchored match. */
  18306. X    s = string;
  18307. X    if (prog->regstart != '\0')
  18308. X        /* We know what char it must start with. */
  18309. X        while ((s = strchr(s, prog->regstart)) != NULL) {
  18310. X            if (regtry(prog, s))
  18311. X                return(1);
  18312. X            s++;
  18313. X        }
  18314. X    else
  18315. X        /* We don't -- general case. */
  18316. X        do {
  18317. X            if (regtry(prog, s))
  18318. X                return(1);
  18319. X        } while (*s++ != '\0');
  18320. X
  18321. X    /* Failure. */
  18322. X    return(0);
  18323. X}
  18324. X
  18325. X/*
  18326. X - regtry - try match at specific point
  18327. X */
  18328. Xstatic int            /* 0 failure, 1 success */
  18329. Xregtry(prog, string)
  18330. Xregexp *prog;
  18331. Xchar *string;
  18332. X{
  18333. X    register int i;
  18334. X    register char **sp;
  18335. X    register char **ep;
  18336. X
  18337. X    reginput = string;
  18338. X    regstartp = prog->startp;
  18339. X    regendp = prog->endp;
  18340. X
  18341. X    sp = prog->startp;
  18342. X    ep = prog->endp;
  18343. X    for (i = NSUBEXP; i > 0; i--) {
  18344. X        *sp++ = NULL;
  18345. X        *ep++ = NULL;
  18346. X    }
  18347. X    if (regmatch(prog->program + 1)) {
  18348. X        prog->startp[0] = string;
  18349. X        prog->endp[0] = reginput;
  18350. X        return(1);
  18351. X    } else
  18352. X        return(0);
  18353. X}
  18354. X
  18355. X/*
  18356. X - regmatch - main matching routine
  18357. X *
  18358. X * Conceptually the strategy is simple:  check to see whether the current
  18359. X * node matches, call self recursively to see whether the rest matches,
  18360. X * and then act accordingly.  In practice we make some effort to avoid
  18361. X * recursion, in particular by going through "ordinary" nodes (that don't
  18362. X * need to know whether the rest of the match failed) by a loop instead of
  18363. X * by recursion.
  18364. X */
  18365. Xstatic int            /* 0 failure, 1 success */
  18366. Xregmatch(prog)
  18367. Xchar *prog;
  18368. X{
  18369. X    register char *scan;    /* Current node. */
  18370. X    char *next;        /* Next node. */
  18371. X    extern char *strchr();
  18372. X
  18373. X    scan = prog;
  18374. X#ifdef DEBUG
  18375. X    if (scan != NULL && regnarrate)
  18376. X        fprintf(stderr, "%s(\n", regprop(scan));
  18377. X#endif
  18378. X    while (scan != NULL) {
  18379. X#ifdef DEBUG
  18380. X        if (regnarrate)
  18381. X            fprintf(stderr, "%s...\n", regprop(scan));
  18382. X#endif
  18383. X        next = regnext(scan);
  18384. X
  18385. X        switch (OP(scan)) {
  18386. X        case BOL:
  18387. X            if (reginput != regbol)
  18388. X                return(0);
  18389. X            break;
  18390. X        case EOL:
  18391. X            if (*reginput != '\0')
  18392. X                return(0);
  18393. X            break;
  18394. X        case ANY:
  18395. X            if (*reginput == '\0')
  18396. X                return(0);
  18397. X            reginput++;
  18398. X            break;
  18399. X        case EXACTLY: {
  18400. X                register int len;
  18401. X                register char *opnd;
  18402. X
  18403. X                opnd = OPERAND(scan);
  18404. X                /* Inline the first character, for speed. */
  18405. X                if (*opnd != *reginput)
  18406. X                    return(0);
  18407. X                len = strlen(opnd);
  18408. X                if (len > 1 && strncmp(opnd, reginput, len) != 0)
  18409. X                    return(0);
  18410. X                reginput += len;
  18411. X            }
  18412. X            break;
  18413. X        case ANYOF:
  18414. X            if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  18415. X                return(0);
  18416. X            reginput++;
  18417. X            break;
  18418. X        case ANYBUT:
  18419. X            if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  18420. X                return(0);
  18421. X            reginput++;
  18422. X            break;
  18423. X        case NOTHING:
  18424. X            break;
  18425. X        case BACK:
  18426. X            break;
  18427. X        case OPEN+1:
  18428. X        case OPEN+2:
  18429. X        case OPEN+3:
  18430. X        case OPEN+4:
  18431. X        case OPEN+5:
  18432. X        case OPEN+6:
  18433. X        case OPEN+7:
  18434. X        case OPEN+8:
  18435. X        case OPEN+9: {
  18436. X                register int no;
  18437. X                register char *save;
  18438. X
  18439. X                no = OP(scan) - OPEN;
  18440. X                save = reginput;
  18441. X
  18442. X                if (regmatch(next)) {
  18443. X                    /*
  18444. X                     * Don't set startp if some later
  18445. X                     * invocation of the same parentheses
  18446. X                     * already has.
  18447. X                     */
  18448. X                    if (regstartp[no] == NULL)
  18449. X                        regstartp[no] = save;
  18450. X                    return(1);
  18451. X                } else
  18452. X                    return(0);
  18453. X            }
  18454. X            break;
  18455. X        case CLOSE+1:
  18456. X        case CLOSE+2:
  18457. X        case CLOSE+3:
  18458. X        case CLOSE+4:
  18459. X        case CLOSE+5:
  18460. X        case CLOSE+6:
  18461. X        case CLOSE+7:
  18462. X        case CLOSE+8:
  18463. X        case CLOSE+9: {
  18464. X                register int no;
  18465. X                register char *save;
  18466. X
  18467. X                no = OP(scan) - CLOSE;
  18468. X                save = reginput;
  18469. X
  18470. X                if (regmatch(next)) {
  18471. X                    /*
  18472. X                     * Don't set endp if some later
  18473. X                     * invocation of the same parentheses
  18474. X                     * already has.
  18475. X                     */
  18476. X                    if (regendp[no] == NULL)
  18477. X                        regendp[no] = save;
  18478. X                    return(1);
  18479. X                } else
  18480. X                    return(0);
  18481. X            }
  18482. X            break;
  18483. X        case BRANCH: {
  18484. X                register char *save;
  18485. X
  18486. X                if (OP(next) != BRANCH)        /* No choice. */
  18487. X                    next = OPERAND(scan);    /* Avoid recursion. */
  18488. X                else {
  18489. X                    do {
  18490. X                        save = reginput;
  18491. X                        if (regmatch(OPERAND(scan)))
  18492. X                            return(1);
  18493. X                        reginput = save;
  18494. X                        scan = regnext(scan);
  18495. X                    } while (scan != NULL && OP(scan) == BRANCH);
  18496. X                    return(0);
  18497. X                    /* NOTREACHED */
  18498. X                }
  18499. X            }
  18500. X            break;
  18501. X        case STAR:
  18502. X        case PLUS: {
  18503. X                register char nextch;
  18504. X                register int no;
  18505. X                register char *save;
  18506. X                register int min;
  18507. X
  18508. X                /*
  18509. X                 * Lookahead to avoid useless match attempts
  18510. X                 * when we know what character comes next.
  18511. X                 */
  18512. X                nextch = '\0';
  18513. X                if (OP(next) == EXACTLY)
  18514. X                    nextch = *OPERAND(next);
  18515. X                min = (OP(scan) == STAR) ? 0 : 1;
  18516. X                save = reginput;
  18517. X                no = regrepeat(OPERAND(scan));
  18518. X                while (no >= min) {
  18519. X                    /* If it could work, try it. */
  18520. X                    if (nextch == '\0' || *reginput == nextch)
  18521. X                        if (regmatch(next))
  18522. X                            return(1);
  18523. X                    /* Couldn't or didn't -- back up. */
  18524. X                    no--;
  18525. X                    reginput = save + no;
  18526. X                }
  18527. X                return(0);
  18528. X            }
  18529. X            break;
  18530. X        case END:
  18531. X            return(1);    /* Success! */
  18532. X            break;
  18533. X        default:
  18534. X            regerror("memory corruption");
  18535. X            return(0);
  18536. X            break;
  18537. X        }
  18538. X
  18539. X        scan = next;
  18540. X    }
  18541. X
  18542. X    /*
  18543. X     * We get here only if there's trouble -- normally "case END" is
  18544. X     * the terminating point.
  18545. X     */
  18546. X    regerror("corrupted pointers");
  18547. X    return(0);
  18548. X}
  18549. X
  18550. X/*
  18551. X - regrepeat - repeatedly match something simple, report how many
  18552. X */
  18553. Xstatic int
  18554. Xregrepeat(p)
  18555. Xchar *p;
  18556. X{
  18557. X    register int count = 0;
  18558. X    register char *scan;
  18559. X    register char *opnd;
  18560. X    extern char *strchr();
  18561. X
  18562. X    scan = reginput;
  18563. X    opnd = OPERAND(p);
  18564. X    switch (OP(p)) {
  18565. X    case ANY:
  18566. X        count = strlen(scan);
  18567. X        scan += count;
  18568. X        break;
  18569. X    case EXACTLY:
  18570. X        while (*opnd == *scan) {
  18571. X            count++;
  18572. X            scan++;
  18573. X        }
  18574. X        break;
  18575. X    case ANYOF:
  18576. X        while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  18577. X            count++;
  18578. X            scan++;
  18579. X        }
  18580. X        break;
  18581. X    case ANYBUT:
  18582. X        while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  18583. X            count++;
  18584. X            scan++;
  18585. X        }
  18586. X        break;
  18587. X    default:        /* Oh dear.  Called inappropriately. */
  18588. X        regerror("internal foulup");
  18589. X        count = 0;    /* Best compromise. */
  18590. X        break;
  18591. X    }
  18592. X    reginput = scan;
  18593. X
  18594. X    return(count);
  18595. X}
  18596. X
  18597. X/*
  18598. X - regnext - dig the "next" pointer out of a node
  18599. X */
  18600. Xstatic char *
  18601. Xregnext(p)
  18602. Xregister char *p;
  18603. X{
  18604. X    register int offset;
  18605. X
  18606. X    if (p == ®dummy)
  18607. X        return(NULL);
  18608. X
  18609. X    offset = NEXT(p);
  18610. X    if (offset == 0)
  18611. X        return(NULL);
  18612. X
  18613. X    if (OP(p) == BACK)
  18614. X        return(p-offset);
  18615. X    else
  18616. X        return(p+offset);
  18617. X}
  18618. X
  18619. X#ifdef DEBUG
  18620. X
  18621. XSTATIC char *regprop();
  18622. X
  18623. X/*
  18624. X - regdump - dump a regexp onto stdout in vaguely comprehensible form
  18625. X */
  18626. Xvoid
  18627. Xregdump(r)
  18628. Xregexp *r;
  18629. X{
  18630. X    register char *s;
  18631. X    register char op = EXACTLY;    /* Arbitrary non-END op. */
  18632. X    register char *next;
  18633. X    extern char *strchr();
  18634. X
  18635. X
  18636. X    s = r->program + 1;
  18637. X    while (op != END) {    /* While that wasn't END last time... */
  18638. X        op = OP(s);
  18639. X        printf("%2d%s", s-r->program, regprop(s));    /* Where, what. */
  18640. X        next = regnext(s);
  18641. X        if (next == NULL)        /* Next ptr. */
  18642. X            printf("(0)");
  18643. X        else 
  18644. X            printf("(%d)", (s-r->program)+(next-s));
  18645. X        s += 3;
  18646. X        if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  18647. X            /* Literal string, where present. */
  18648. X            while (*s != '\0') {
  18649. X                putchar(*s);
  18650. X                s++;
  18651. X            }
  18652. X            s++;
  18653. X        }
  18654. X        putchar('\n');
  18655. X    }
  18656. X
  18657. X    /* Header fields of interest. */
  18658. X    if (r->regstart != '\0')
  18659. X        printf("start `%c' ", r->regstart);
  18660. X    if (r->reganch)
  18661. X        printf("anchored ");
  18662. X    if (r->regmust != NULL)
  18663. X        printf("must have \"%s\"", r->regmust);
  18664. X    printf("\n");
  18665. X}
  18666. X
  18667. X/*
  18668. X - regprop - printable representation of opcode
  18669. X */
  18670. Xstatic char *
  18671. Xregprop(op)
  18672. Xchar *op;
  18673. X{
  18674. X    register char *p;
  18675. X    static char buf[50];
  18676. X
  18677. X    (void) strcpy(buf, ":");
  18678. X
  18679. X    switch (OP(op)) {
  18680. X    case BOL:
  18681. X        p = "BOL";
  18682. X        break;
  18683. X    case EOL:
  18684. X        p = "EOL";
  18685. X        break;
  18686. X    case ANY:
  18687. X        p = "ANY";
  18688. X        break;
  18689. X    case ANYOF:
  18690. X        p = "ANYOF";
  18691. X        break;
  18692. X    case ANYBUT:
  18693. X        p = "ANYBUT";
  18694. X        break;
  18695. X    case BRANCH:
  18696. X        p = "BRANCH";
  18697. X        break;
  18698. X    case EXACTLY:
  18699. X        p = "EXACTLY";
  18700. X        break;
  18701. X    case NOTHING:
  18702. X        p = "NOTHING";
  18703. X        break;
  18704. X    case BACK:
  18705. X        p = "BACK";
  18706. X        break;
  18707. X    case END:
  18708. X        p = "END";
  18709. X        break;
  18710. X    case OPEN+1:
  18711. X    case OPEN+2:
  18712. X    case OPEN+3:
  18713. X    case OPEN+4:
  18714. X    case OPEN+5:
  18715. X    case OPEN+6:
  18716. X    case OPEN+7:
  18717. X    case OPEN+8:
  18718. X    case OPEN+9:
  18719. X        sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
  18720. X        p = NULL;
  18721. X        break;
  18722. X    case CLOSE+1:
  18723. X    case CLOSE+2:
  18724. X    case CLOSE+3:
  18725. X    case CLOSE+4:
  18726. X    case CLOSE+5:
  18727. X    case CLOSE+6:
  18728. X    case CLOSE+7:
  18729. X    case CLOSE+8:
  18730. X    case CLOSE+9:
  18731. X        sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
  18732. X        p = NULL;
  18733. X        break;
  18734. X    case STAR:
  18735. X        p = "STAR";
  18736. X        break;
  18737. X    case PLUS:
  18738. X        p = "PLUS";
  18739. X        break;
  18740. X    default:
  18741. X        regerror("corrupted opcode");
  18742. X        break;
  18743. X    }
  18744. X    if (p != NULL)
  18745. X        (void) strcat(buf, p);
  18746. X    return(buf);
  18747. X}
  18748. X#endif
  18749. X
  18750. X/*
  18751. X * The following is provided for those people who do not have strcspn() in
  18752. X * their C libraries.  They should get off their butts and do something
  18753. X * about it; at least one public-domain implementation of those (highly
  18754. X * useful) string routines has been published on Usenet.
  18755. X */
  18756. X#ifdef STRCSPN
  18757. X/*
  18758. X * strcspn - find length of initial segment of s1 consisting entirely
  18759. X * of characters not from s2
  18760. X */
  18761. X
  18762. Xstatic int
  18763. Xstrcspn(s1, s2)
  18764. Xchar *s1;
  18765. Xchar *s2;
  18766. X{
  18767. X    register char *scan1;
  18768. X    register char *scan2;
  18769. X    register int count;
  18770. X
  18771. X    count = 0;
  18772. X    for (scan1 = s1; *scan1 != '\0'; scan1++) {
  18773. X        for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  18774. X            if (*scan1 == *scan2++)
  18775. X                return(count);
  18776. X        count++;
  18777. X    }
  18778. X    return(count);
  18779. X}
  18780. X#endif
  18781. *-*-END-of-src/regexp.c-*-*
  18782. echo x - src/regsub.c
  18783. sed 's/^X//' >src/regsub.c <<'*-*-END-of-src/regsub.c-*-*'
  18784. X/*
  18785. X * regsub
  18786. X *
  18787. X *    Copyright (c) 1986 by University of Toronto.
  18788. X *    Written by Henry Spencer.  Not derived from licensed software.
  18789. X *
  18790. X *    Permission is granted to anyone to use this software for any
  18791. X *    purpose on any computer system, and to redistribute it freely,
  18792. X *    subject to the following restrictions:
  18793. X *
  18794. X *    1. The author is not responsible for the consequences of use of
  18795. X *        this software, no matter how awful, even if they arise
  18796. X *        from defects in it.
  18797. X *
  18798. X *    2. The origin of this software must not be misrepresented, either
  18799. X *        by explicit claim or by omission.
  18800. X *
  18801. X *    3. Altered versions must be plainly marked as such, and must not
  18802. X *        be misrepresented as being the original software.
  18803. X */
  18804. X#include <stdio.h>
  18805. X#include "regexp.h"
  18806. X#include "regmagic.h"
  18807. X
  18808. X#ifndef CHARBITS
  18809. X#define    UCHARAT(p)    ((int)*(unsigned char *)(p))
  18810. X#else
  18811. X#define    UCHARAT(p)    ((int)*(p)&CHARBITS)
  18812. X#endif
  18813. X
  18814. X/*
  18815. X - regsub - perform substitutions after a regexp match
  18816. X */
  18817. Xvoid
  18818. Xregsub(prog, source, dest)
  18819. Xregexp *prog;
  18820. Xchar *source;
  18821. Xchar *dest;
  18822. X{
  18823. X    register char *src;
  18824. X    register char *dst;
  18825. X    register char c;
  18826. X    register int no;
  18827. X    register int len;
  18828. X    extern char *strncpy();
  18829. X
  18830. X    if (prog == NULL || source == NULL || dest == NULL) {
  18831. X        regerror("NULL parm to regsub");
  18832. X        return;
  18833. X    }
  18834. X    if (UCHARAT(prog->program) != MAGIC) {
  18835. X        regerror("damaged regexp fed to regsub");
  18836. X        return;
  18837. X    }
  18838. X
  18839. X    src = source;
  18840. X    dst = dest;
  18841. X    while ((c = *src++) != '\0') {
  18842. X        if (c == '&')
  18843. X            no = 0;
  18844. X        else if (c == '\\' && '0' <= *src && *src <= '9')
  18845. X            no = *src++ - '0';
  18846. X        else
  18847. X            no = -1;
  18848. X
  18849. X        if (no < 0) {    /* Ordinary character. */
  18850. X            if (c == '\\' && (*src == '\\' || *src == '&'))
  18851. X                c = *src++;
  18852. X            *dst++ = c;
  18853. X        }
  18854. X        else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
  18855. X            len = prog->endp[no] - prog->startp[no];
  18856. X            (void) strncpy(dst, prog->startp[no], len);
  18857. X            dst += len;
  18858. X            if (len != 0 && *(dst-1) == '\0') {        /* strncpy hit NUL. */
  18859. X                regerror("damaged match string");
  18860. X                return;
  18861. X            }
  18862. X        }
  18863. X    }
  18864. X    *dst++ = '\0';
  18865. X}
  18866. *-*-END-of-src/regsub.c-*-*
  18867. echo x - src/rev.c
  18868. sed 's/^X//' >src/rev.c <<'*-*-END-of-src/rev.c-*-*'
  18869. X/*
  18870. X  ----------------------------------------------------------------------------
  18871. X  |               REVERSE ORDER OF INPUT                 |
  18872. X  |                                         |
  18873. X  |                Version 1.0                     |
  18874. X  |                                         |
  18875. X  |                (or, when Computer Science gets to you)                   |
  18876. X  |                                         |
  18877. X  |               Written by Anastasios Kotsikonas                      |
  18878. X  |                      (tasos@cs.bu.edu)                          |
  18879. X  |                                                                         |
  18880. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  18881. X  | whole and not in parts, as long as you do not remove or alter the author |
  18882. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  18883. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  18884. X  | provided for your personal use, you may not alter the functions          |
  18885. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  18886. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  18887. X  | any changes you may have made. No part of the source code bearing a         |
  18888. X  | copyright notice can be included in commercial software systems without  |
  18889. X  | written permission by the author.                         |
  18890. X  | By using this software you are bound by this agreement.                  |
  18891. X  | This software comes with no warranties and cannot be sold for profit.    |
  18892. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  18893. X  | files when distributing this software.                                   |
  18894. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  18895. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  18896. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  18897. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  18898. X  | (ii).                                                                    |
  18899. X  ----------------------------------------------------------------------------
  18900. X*/
  18901. X
  18902. X#include <stdio.h>
  18903. X
  18904. Xmain ()
  18905. X{
  18906. X  char linein[65536];
  18907. X  char lineout[65536];
  18908. X  long int i, j;
  18909. X
  18910. X  while (!feof (stdin)) {
  18911. X    linein[0] = lineout[0] = '\0';
  18912. X    fgets (linein, 65535, stdin);
  18913. X    j = strlen (linein);
  18914. X    if (j && linein [j - 1] == '\n')
  18915. X      lineout [j - 1]= '\n',
  18916. X      --j;
  18917. X    for (i = j - 1, j = 0; i >= 0; i--)
  18918. X      lineout[j++] = linein[i];
  18919. X    if (lineout[j] == '\n') j++;
  18920. X    lineout[j] = '\0';
  18921. X    fputs (lineout, stdout);
  18922. X  }
  18923. X  exit (0);
  18924. X}
  18925. *-*-END-of-src/rev.c-*-*
  18926. echo x - src/sem.c
  18927. sed 's/^X//' >src/sem.c <<'*-*-END-of-src/sem.c-*-*'
  18928. X/*
  18929. X  ----------------------------------------------------------------------------
  18930. X  |                SEMAPHORE OPERATIONS                 |
  18931. X  |                                         |
  18932. X  |                     version 1.0                 |
  18933. X  |                                         |
  18934. X  | User contributed code.                             |
  18935. X  | Author: Thimios Panagos <thimios@cs.bu.edu>                     |
  18936. X  ----------------------------------------------------------------------------
  18937. X*/
  18938. X
  18939. X#include <signal.h>
  18940. X#include "defs.h"
  18941. X#ifdef GO_INTERACTIVE
  18942. X# include <stdio.h>
  18943. X# include <sys/types.h>
  18944. X# include <sys/ipc.h>
  18945. X# include <sys/sem.h>
  18946. X
  18947. Xint semtran (int);
  18948. Xint semcall (int, int);
  18949. Xint P (int, int);
  18950. Xint V (int, int);
  18951. Xvoid semremove (int);
  18952. X
  18953. X/*
  18954. X  Create a semaphore. Return the semaphore id, or -1 on error.
  18955. X*/
  18956. X
  18957. Xint semtran (int key) 
  18958. X{
  18959. X  int sid;
  18960. X
  18961. X  if ((sid = semget ((key_t) key, 1, 0600 | IPC_CREAT | SEM_UNDO)) < 0)
  18962. X    return -1;
  18963. X  return sid;
  18964. X}
  18965. X
  18966. X/*
  18967. X  Operate on a semaphore (increment or decrement).
  18968. X*/
  18969. X
  18970. Xint semcall (int sid, int op)
  18971. X{
  18972. X  struct sembuf sb;
  18973. X
  18974. X  sb.sem_num = sb.sem_flg = 0;
  18975. X  sb.sem_op = op;
  18976. X
  18977. X  if (semop (sid, &sb, 1) == -1)
  18978. X    return -1;
  18979. X  return 0;
  18980. X}
  18981. X
  18982. X/*
  18983. X  P semaphore; call when attempting to get into critical section.
  18984. X*/
  18985. X
  18986. Xint P (int sid, int op)
  18987. X{
  18988. X  if (semcall (sid, op))
  18989. X    return -1;
  18990. X  return 0;
  18991. X}
  18992. X
  18993. X/*
  18994. X  V semaphore; call when out of critical section.
  18995. X*/
  18996. X
  18997. Xint V (int sid, int op)
  18998. X{
  18999. X  if (semcall (sid, -op))
  19000. X    return -1;
  19001. X  return 0;
  19002. X}
  19003. X
  19004. X/*
  19005. X  Destroy a semaphore.
  19006. X*/
  19007. X
  19008. Xvoid semremove (int sid)
  19009. X{
  19010. X  (void) semctl (sid, 0, IPC_RMID, 0); 
  19011. X}
  19012. X#endif
  19013. *-*-END-of-src/sem.c-*-*
  19014. echo x - src/semset.c
  19015. sed 's/^X//' >src/semset.c <<'*-*-END-of-src/semset.c-*-*'
  19016. X/*
  19017. X  ----------------------------------------------------------------------------
  19018. X  |                    Semaphore manipulation UTILITY                  |
  19019. X  |                                                                          |
  19020. X  |                              Version 1.0                                 |
  19021. X  |                                                                          |
  19022. X  |                (or, when Computer Science gets to you)                   |
  19023. X  |                                                                          |
  19024. X  |                    Written by Anastasios Kotsikonas                      |
  19025. X  |                           (tasos@cs.bu.edu)                              |
  19026. X  |                                                                          |
  19027. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  19028. X  | whole and not in parts, as long as you do not remove or alter the author |
  19029. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  19030. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  19031. X  | provided for your personal use, you may not alter the functions          |
  19032. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  19033. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  19034. X  | any changes you may have made. No part of the source code bearing a         |
  19035. X  | copyright notice can be included in commercial software systems without  |
  19036. X  | written permission by the author.                         |
  19037. X  | By using this software you are bound by this agreement.                  |
  19038. X  | This software comes with no warranties and cannot be sold for profit.    |
  19039. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  19040. X  | files when distributing this software.                                   |
  19041. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  19042. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  19043. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  19044. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  19045. X  | (ii).                                                                    |
  19046. X  ----------------------------------------------------------------------------
  19047. X
  19048. X  Use this utility to check and reset (if necessary) the concurrency control
  19049. X  of the system. If some process seems "stuck", use semset with the semaphore
  19050. X  id to determine what it is doing. To reset use a value of zero:
  19051. X
  19052. X  % semset
  19053. X
  19054. X  will invoke ipcs -s and show you all current semapahores.
  19055. X
  19056. X  % semset semid
  19057. X
  19058. X  will show you the current value and flags for the particular semaphore.
  19059. X
  19060. X  $ semset semid value
  19061. X
  19062. X  will show the current value and flags, then reset its value to the desired
  19063. X  one.
  19064. X*/
  19065. X
  19066. X#include <stdio.h>
  19067. X#include <signal.h>
  19068. X#include "defs.h"
  19069. X
  19070. X#ifdef GO_INTERACTIVE
  19071. X# include <sys/types.h>
  19072. X# include <sys/ipc.h>
  19073. X# include <sys/sem.h>
  19074. X
  19075. Xmain (int argc, char **argv)
  19076. X{
  19077. X  union semun {
  19078. X    int val;
  19079. X    struct semid_ds *buf;
  19080. X    ushort *array;
  19081. X  } sem;
  19082. X
  19083. X  if (argc < 2)
  19084. X    system ("ipcs -sa"),
  19085. X    exit (0);
  19086. X  if (!strcmp (argv [1], "-u"))
  19087. X    fprintf (stderr, "Usage: %s [semaphore id [new value]]\n", argv [0]),
  19088. X    exit (3);
  19089. X  if ((sem.val = semctl (atoi (argv [1]), 0, GETVAL, 0)) < 0)
  19090. X    perror ("semctl()"),
  19091. X    exit (1);
  19092. X  printf ("Current value: 0x%x", sem.val);
  19093. X  eval (sem.val);
  19094. X  printf ("\n");
  19095. X  if (argc >= 3) {
  19096. X    sem.val = atoi (argv[2]);
  19097. X    if (semctl (atoi (argv [1]), 0, SETVAL, sem))
  19098. X      perror ("semctl()"),
  19099. X      exit (1);
  19100. X    printf ("New value: 0x%x", sem.val);
  19101. X    eval (sem.val);
  19102. X    printf ("\n");
  19103. X  }
  19104. X  exit (0);
  19105. X}
  19106. X
  19107. Xeval (int val)
  19108. X{
  19109. X  if (val) {
  19110. X    printf ("; flags on:");
  19111. X    if (val & SEM_REQ_ID)
  19112. X      printf (" SEM_REQ_ID");
  19113. X    if (val & SEM_SYSFILES)
  19114. X      printf (" SEM_SYSFILES");
  19115. X    if (val & SEM_LISTFILES)
  19116. X      printf (" SEM_LISTFILES");
  19117. X    if (val & SEM_ARCHIVES)
  19118. X      printf (" SEM_ARCHIVES");
  19119. X    if (val & SEM_DLVR_MAIL)
  19120. X      printf (" SEM_DLVR_MAIL");
  19121. X  }
  19122. X}
  19123. X#else
  19124. Xmain ()
  19125. X{
  19126. X  printf ("The system does not go live.\n");
  19127. X  exit (0);
  19128. X}
  19129. X#endif
  19130. *-*-END-of-src/semset.c-*-*
  19131. echo x - src/sender.c
  19132. sed 's/^X//' >src/sender.c <<'*-*-END-of-src/sender.c-*-*'
  19133. X/*
  19134. X  ----------------------------------------------------------------------------
  19135. X  |                      SENDER ORIENTED FUNCTIONS                 |
  19136. X  |                                                                          |
  19137. X  |                              Version 2.4                                 |
  19138. X  |                                                                          |
  19139. X  |                (or, when Computer Science gets to you)                   |
  19140. X  |                                                                          |
  19141. X  |                    Written by Anastasios Kotsikonas                      |
  19142. X  |                           (tasos@cs.bu.edu)                              |
  19143. X  |                                                                          |
  19144. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  19145. X  | whole and not in parts, as long as you do not remove or alter the author |
  19146. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  19147. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  19148. X  | provided for your personal use, you may not alter the functions          |
  19149. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  19150. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  19151. X  | any changes you may have made. No part of the source code bearing a         |
  19152. X  | copyright notice can be included in commercial software systems without  |
  19153. X  | written permission by the author.                         |
  19154. X  | By using this software you are bound by this agreement.                  |
  19155. X  | This software comes with no warranties and cannot be sold for profit.    |
  19156. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  19157. X  | files when distributing this software.                                   |
  19158. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  19159. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  19160. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  19161. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  19162. X  | (ii).                                                                    |
  19163. X  ----------------------------------------------------------------------------
  19164. X*/
  19165. X
  19166. X#include <stdio.h>
  19167. X#ifndef unknown_port
  19168. X# ifndef __NeXT__
  19169. X#  include <unistd.h>
  19170. X# else
  19171. X#  include <libc.h>
  19172. X# endif
  19173. X#endif
  19174. X#include <string.h>
  19175. X#include <ctype.h>
  19176. X#include <errno.h>
  19177. X#ifdef unknown_port
  19178. Xextern int errno;
  19179. X#endif
  19180. X#include <signal.h>
  19181. X#include "defs.h"
  19182. X
  19183. X#ifdef GO_INTERACTIVE
  19184. Xextern int sid;
  19185. X# include <sys/types.h>
  19186. X# include <sys/ipc.h>
  19187. X# include <sys/sem.h>
  19188. X# ifndef SYSLOG
  19189. X#  define IN_CRITICAL_SECTION(__func__, mask)\
  19190. X  if (sid >= 0) {\
  19191. X    int val;\
  19192. X    while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
  19193. X    if (P (sid, (mask)) < 0)\
  19194. X      report_progress (report, tsprintf ("\n%s(): Error P(); errno %d",\
  19195. X                     __func__, errno), TRUE),\
  19196. X      fclose (report),\
  19197. X      exit (14);\
  19198. X  }
  19199. X# else
  19200. X#  define IN_CRITICAL_SECTION(__func__, mask)\
  19201. X  if (sid >= 0) {\
  19202. X    int val;\
  19203. X    while ((val = semctl (sid, 0, GETVAL)) >= 0 && (val & (mask)));\
  19204. X    if (P (sid, (mask)) < 0)\
  19205. X      report_progress (report, tsprintf ("\n%s(): Error P(); errno %d",\
  19206. X                     __func__, errno), TRUE),\
  19207. X      exit (14);\
  19208. X  }
  19209. X# endif
  19210. X
  19211. X# ifndef SYSLOG
  19212. X#  define OUT_OF_CRITICAL_SECTION(__func__, mask)\
  19213. X  if (sid >= 0)\
  19214. X    if (V (sid, (mask)) < 0)\
  19215. X      report_progress (report, tsprintf ("\n%s(): Error V(); errno %d",\
  19216. X                     __func__, errno), TRUE),\
  19217. X      fclose (report),\
  19218. X      exit (14);
  19219. X# else
  19220. X#  define OUT_OF_CRITICAL_SECTION(__func__, mask)\
  19221. X  if (sid >= 0)\
  19222. X    if (V (sid, (mask)) < 0)\
  19223. X      report_progress (report, tsprintf ("\n%s(): Error V(); errno %d",\
  19224. X                     __func__, errno), TRUE),\
  19225. X      exit (14);
  19226. X# endif
  19227. X#endif
  19228. X
  19229. X#define    _SUBSCRIBERS    1
  19230. X#define    _ALIASES    2
  19231. X#define    OTHER        3
  19232. X
  19233. Xextern FILE *report;
  19234. X
  19235. X#ifdef __STDC__
  19236. Xextern  char *tsprintf (char *, ...);
  19237. X#else
  19238. Xextern  char *tsprintf ();
  19239. X#endif
  19240. Xextern  char **alternate_addresses;
  19241. X
  19242. Xextern  void report_progress (FILE *, char *, int);
  19243. Xextern  char *upcase (char *);
  19244. Xextern  int  gexit (int);
  19245. Xextern  int  re_strcmp (char *, char *, char *);
  19246. Xextern  int P (int, int);
  19247. Xextern  int V (int, int);
  19248. Xextern  char *mystrdup (char *);
  19249. X
  19250. XBOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *, BOOLEAN);
  19251. XBOOLEAN check_file (FILE *, char *, char *, BOOLEAN);
  19252. XBOOLEAN ignore_sender (FILE *, char *, FILE *, BOOLEAN);
  19253. XBOOLEAN owner_listed (char *, char *, char *, FILE *);
  19254. XBOOLEAN host_listed (char *, char *, FILE *);
  19255. Xvoid    check_aliases (char *, char *);
  19256. XBOOLEAN extract_sender (char *);
  19257. XBOOLEAN extract_subscriber (FILE *, char *, BOOLEAN);
  19258. Xvoid    extract_origin (char *);
  19259. Xvoid    extract_address (char *);
  19260. Xvoid    escape_address (char *);
  19261. X
  19262. X/*
  19263. X  Check if 'sender' is subscribed. Return SUBSCRIBED, NEWS, PEER or
  19264. X  NOTSUBSCRIBED. Comparisons are done in upper case.
  19265. X*/
  19266. X
  19267. XBOOLEAN subscribed (FILE *report, char *sender, char *Subscribersf,
  19268. X            char *Newsf, char *Peersf, char *Aliasesf,
  19269. X            BOOLEAN block_sem)
  19270. X{
  19271. X  int code;
  19272. X  if (!Subscribersf) /* call made by distribute () in listproc.c */
  19273. X    return NOTSUBSCRIBED;
  19274. X#ifdef GO_INTERACTIVE
  19275. X  if (block_sem) {
  19276. X    IN_CRITICAL_SECTION ("subscribed", SEM_LISTFILES);
  19277. X  }
  19278. X#endif
  19279. X  alternate_addresses = NULL;
  19280. X  if (check_file (report, sender, Subscribersf, _SUBSCRIBERS) ||
  19281. X      (check_file (report, sender, Aliasesf, _ALIASES) &&
  19282. X       check_file (report, sender, Subscribersf, _SUBSCRIBERS)))
  19283. X    code = SUBSCRIBED;
  19284. X  else if (Newsf &&
  19285. X       (check_file (report, sender, Newsf, OTHER) ||
  19286. X        (check_file (report, sender, Aliasesf, _ALIASES) &&
  19287. X         check_file (report, sender, Newsf, OTHER))))
  19288. X    code = NEWS;
  19289. X  else if (Peersf &&
  19290. X       (check_file (report, sender, Peersf, OTHER) ||
  19291. X        (check_file (report, sender, Aliasesf, _ALIASES) &&
  19292. X         check_file (report, sender, Peersf, OTHER))))
  19293. X    code = PEER;
  19294. X  else
  19295. X    code = NOTSUBSCRIBED;
  19296. X#ifdef GO_INTERACTIVE
  19297. X  if (block_sem) {
  19298. X    OUT_OF_CRITICAL_SECTION ("subscribed", SEM_LISTFILES);
  19299. X  }
  19300. X#endif
  19301. X  return code;
  19302. X}
  19303. X
  19304. X/*
  19305. X  Check the given file for subscription. If the file is an aliases file
  19306. X  and the sender is listed in there, store his actual mailing address
  19307. X  in 'sender'.
  19308. X*/
  19309. X
  19310. XBOOLEAN check_file (FILE *report, char *sender, char *file,
  19311. X            BOOLEAN which_file)
  19312. X{
  19313. X  char subscriber [MAX_LINE];
  19314. X  char sender_copy [MAX_LINE];
  19315. X  char mode [MAX_LINE];
  19316. X  char othermode [MAX_LINE];
  19317. X  char name [MAX_LINE];
  19318. X  char *at, *dot, *s;
  19319. X  FILE *f;
  19320. X  int i, nmatches = 0;
  19321. X  extern char password_in_sub_file [];
  19322. X
  19323. X  if (file == NULL || *sender == EOS) /* serverd does not check the aliases files */
  19324. X    return NOTSUBSCRIBED;
  19325. X  OPEN_FILE (f, file, "r", "check_file");
  19326. X  upcase (sender);          /* Convert to upper case */
  19327. X  while (!feof (f)) {  /* Check list of subscribers/peers/news/aliases */
  19328. X    subscriber[0] = mode[0] = othermode[0] = RESET (name);
  19329. X    extract_subscriber (f, subscriber, (which_file == _ALIASES ? TRUE : FALSE));
  19330. X    if (subscriber[0] != EOS) {
  19331. X      fscanf (f, "%s ", mode);
  19332. X      if (which_file == _SUBSCRIBERS) /* Only this file may have more options */
  19333. X        for (i = 1; i < MAX_SET_OPTIONS - 1; i++) {
  19334. X          fscanf (f, "%s ", othermode);
  19335. X      if (i == 1) /* Save user's password */
  19336. X        strcpy (password_in_sub_file, othermode);
  19337. X        }
  19338. X      if (which_file != _ALIASES)
  19339. X        fgets (name, MAX_LINE - 2, f);
  19340. X      upcase (subscriber);
  19341. X      if ((which_file == _ALIASES && re_strcmp (subscriber, sender, mode) > 0)
  19342. X      || (which_file != _ALIASES && !strcmp (subscriber, sender))) {
  19343. X        fclose (f);
  19344. X        if (which_file == _ALIASES)
  19345. X      upcase (mode),
  19346. X      strcpy (sender, mode); /* Note: mode now is address-as-subscribed */
  19347. X        return SUBSCRIBED;
  19348. X      }
  19349. X      strcpy (sender_copy, sender);
  19350. X      if ((at = strchr (sender_copy, '@')) && (dot = strchr (at, '.')) &&
  19351. X      at != dot + 1) {
  19352. X    sprintf (at + 1, ".*%s", (s = mystrdup (dot + 1)));
  19353. X    free ((char *) s);
  19354. X    if (re_strcmp (sender_copy, subscriber, NULL) > 0) {
  19355. X      if (!alternate_addresses) {
  19356. X        if ((alternate_addresses = (char **) malloc (2 * sizeof (char *)))
  19357. X        == NULL)
  19358. X          report_progress (report, "\ncheck_file(): malloc() failed", TRUE),
  19359. X          gexit (11);
  19360. X      }
  19361. X      else
  19362. X        if ((alternate_addresses = (char **)
  19363. X         realloc ((char **) alternate_addresses,
  19364. X              sizeof (char *) * (nmatches + 2))) == NULL)
  19365. X          report_progress (report, "\ncheck_file(): realloc() failed", TRUE),
  19366. X          gexit (11);
  19367. X      alternate_addresses [nmatches + 1] = NULL;
  19368. X      alternate_addresses [nmatches] = (char *)
  19369. X        malloc ((strlen (subscriber) + 1) * sizeof (char));
  19370. X      strcpy (alternate_addresses [nmatches++], subscriber);
  19371. X    }
  19372. X      }
  19373. X    }
  19374. X  }
  19375. X  fclose (f);
  19376. X  return NOTSUBSCRIBED;
  19377. X}
  19378. X
  19379. X/*
  19380. X  Check if 'sender' appears in the IGNORED file or MESSAGE_IDS.
  19381. X*/
  19382. X
  19383. XBOOLEAN ignore_sender (FILE *ignored, char *sender, FILE *report,
  19384. X               BOOLEAN literal_match)
  19385. X{
  19386. X  char ignored_user [MAX_LINE];
  19387. X  char line[MAX_LINE];
  19388. X
  19389. X  rewind (ignored);
  19390. X  while (!feof (ignored)) { /* Check the IGNORED file first */
  19391. X    line[0] = RESET (ignored_user);
  19392. X    fgets (line, MAX_LINE - 2, ignored);
  19393. X    sscanf (line, "%s", ignored_user);
  19394. X    upcase (ignored_user);
  19395. X    if (ignored_user[0] != EOS) {
  19396. X      if (!literal_match) {
  19397. X    if (re_strcmp (ignored_user, sender, NULL) > 0) {
  19398. X      report_progress (report, tsprintf ("User %s and message ignored.\n",
  19399. X                         sender), FALSE);
  19400. X      return TRUE;
  19401. X    }
  19402. X      }
  19403. X      else if (!strcmp (ignored_user, sender)) {
  19404. X    report_progress (report, tsprintf ("User %s and message ignored.\n",
  19405. X                       sender), FALSE);
  19406. X    return TRUE;
  19407. X      }
  19408. X    }
  19409. X  }
  19410. X  return FALSE;
  19411. X}
  19412. X
  19413. X/*
  19414. X  Check whether the list 'owner' is listed.
  19415. X*/
  19416. X
  19417. XBOOLEAN owner_listed (char *owners, char *owner, char *list, FILE *report)
  19418. X{
  19419. X  char registered_owner [MAX_LINE];
  19420. X  char assigned_list [MAX_LINE];
  19421. X  char line [MAX_LINE];
  19422. X  FILE *f;
  19423. X
  19424. X  OPEN_FILE (f, owners, "r", "owner_listed");
  19425. X  while (!feof (f)) {
  19426. X    line[0] = assigned_list[0] = RESET (registered_owner);
  19427. X    fgets (line, MAX_LINE - 2, f);
  19428. X    sscanf (line, "%s %s", registered_owner, assigned_list);
  19429. X    upcase (registered_owner);
  19430. X    upcase (assigned_list);
  19431. X    if (registered_owner[0] != EOS)
  19432. X      if (!strcmp (registered_owner, owner) && !strcmp (assigned_list, list)) {
  19433. X    fclose (f);
  19434. X    return OWNER;
  19435. X      }
  19436. X  }
  19437. X  fclose (f);
  19438. X  return FALSE;
  19439. X}
  19440. X
  19441. X/*
  19442. X  Check whether the given host appears in a hosts file.
  19443. X*/
  19444. X
  19445. XBOOLEAN host_listed (char *hosts, char *host, FILE *report)
  19446. X{
  19447. X  char _host [MAX_LINE];
  19448. X  FILE* f;
  19449. X
  19450. X  OPEN_FILE (f, hosts, "r", "host_listed");
  19451. X  while (!feof (f)) {
  19452. X    RESET (_host);
  19453. X    fscanf (f, "%s", _host);
  19454. X    upcase (_host);
  19455. X    if (_host[0] == '#') {
  19456. X      fgets (_host, MAX_LINE - 2, f);
  19457. X      continue;
  19458. X    }
  19459. X    if (_host[0] != EOS && re_strcmp (_host, host, NULL) > 0) {
  19460. X      fclose (f);
  19461. X      return TRUE;
  19462. X    }
  19463. X  }
  19464. X  fclose (f);
  19465. X  return FALSE;
  19466. X}
  19467. X
  19468. X/*
  19469. X  Look up 'sender' in the 'aliases' file. If a match is found, use
  19470. X  the alternate address.
  19471. X*/
  19472. X
  19473. Xvoid check_aliases (char *aliases, char *sender)
  19474. X{
  19475. X  char line [MAX_LINE];
  19476. X  char newalias [MAX_LINE];
  19477. X  char alias [MAX_LINE];
  19478. X  FILE *f;
  19479. X
  19480. X  if ((f = fopen (aliases, "r")) == NULL)
  19481. X    return;
  19482. X#ifdef GO_INTERACTIVE
  19483. X  IN_CRITICAL_SECTION ("check_aliases", SEM_LISTFILES);
  19484. X#endif
  19485. X  upcase (sender);
  19486. X  while (!feof (f)) {
  19487. X    line[0] = alias[0] = RESET (newalias);
  19488. X    fgets (line, MAX_LINE - 2, f);
  19489. X    sscanf (line, "%s %s", alias, newalias);
  19490. X    upcase (alias);
  19491. X    if (alias[0] != EOS)
  19492. X      if (re_strcmp (alias, sender, newalias) > 0)
  19493. X    upcase (newalias),
  19494. X    strcpy (sender, newalias);
  19495. X  }
  19496. X  fclose (f);
  19497. X#ifdef GO_INTERACTIVE
  19498. X  OUT_OF_CRITICAL_SECTION ("check_aliases", SEM_LISTFILES);
  19499. X#endif
  19500. X  return;
  19501. X}
  19502. X
  19503. X/*
  19504. X  Extract the sender's email address. To do that, skip over the leading
  19505. X  "From ". That's where the address starts. Then put an EOS character at
  19506. X  the end of this address (a blank terminates this address string).
  19507. X  Addresses that contain single quotes are treated as invalid (contrary to
  19508. X  RFC 822 specs) since they create problems with the shell.
  19509. X*/
  19510. X
  19511. XBOOLEAN extract_sender (char *s)
  19512. X{
  19513. X  int nsquote = 0, ndquote = 0, nparen = 0, nangle = 0, nsquare = 0;
  19514. X  BOOLEAN done = FALSE, invalid_char = FALSE;
  19515. X  char *r = s;
  19516. X#ifdef DEBUG
  19517. X  char *p = s + strlen (s);
  19518. X#endif
  19519. X
  19520. X  if (strncmp (s, START_OF_MESSAGE, strlen (START_OF_MESSAGE))) {
  19521. X    s [strlen (START_OF_MESSAGE)] = EOS;
  19522. X    return FALSE;
  19523. X  }
  19524. X  sprintf (s, "%s", s + strlen (START_OF_MESSAGE));
  19525. X  while (*s != EOS && !done) { /* Look for end of address substring */
  19526. X    (*s == '`' || *s == '*' || *s == '?' || *s == '|' ? invalid_char = TRUE : 0);
  19527. X/*
  19528. X    (*s == '/' && (s == r || *(s - 1) == ';') ? invalid_char = TRUE : 0);
  19529. X*/
  19530. X    (*s == '\'' ? (nsquote = 1) : 0);
  19531. X    (*s == '\"' ? (s != r ? (*(s - 1) != '\\' ? (ndquote = !ndquote) : 0) :
  19532. X           (ndquote = !ndquote)) : 0);
  19533. X    (*s == '(' ? (!ndquote ? ++nparen : 0) : 0);
  19534. X    (*s == ')' ? (!ndquote ? --nparen : 0) : 0);
  19535. X    (*s == '<' ? (!ndquote ? ++nangle : 0) : 0);
  19536. X    (*s == '>' ? (!ndquote ? --nangle : 0) : 0);
  19537. X    (*s == '[' ? (!ndquote ? ++nsquare : 0): 0);
  19538. X    (*s == ']' ? (!ndquote ? --nsquare : 0) : 0);
  19539. X    (isspace (*s) ?
  19540. X     ((ndquote || nparen || nangle || nsquare) ? 0 : (done = TRUE)) : 0);
  19541. X    ++s;
  19542. X#ifdef DEBUG
  19543. X    if (s > p) { /* Beyond EOS */
  19544. X      extern FILE *report;
  19545. X      report_progress (report, "extract_sender(): memory being overwritten",
  19546. X                       TRUE);
  19547. X    }
  19548. X#endif
  19549. X  }
  19550. X  *(s - 1) = EOS;  /* 's' is now pointing to the sender's address */
  19551. X  if (nsquote || ndquote || nparen || nangle || nsquare || invalid_char)
  19552. X    return FALSE;    /* Error in address */
  19553. X  return TRUE;
  19554. X}
  19555. X
  19556. X/*
  19557. X  Extract the subscriber's address from the file. Addresses that contain
  19558. X  single quotes are treated as invalid (contrary to RFC 822 specs) since they
  19559. X  create problems with the shell.
  19560. X*/
  19561. X
  19562. XBOOLEAN extract_subscriber (FILE *f, char *subscriber, BOOLEAN aliases_file)
  19563. X{
  19564. X  int ndquote = 0, nparen = 0, nangle = 0, nsquare = 0, i = 0;
  19565. X  int nsquote = 0;
  19566. X  BOOLEAN done = FALSE, invalid_char = FALSE;
  19567. X  char c = EOS, pc;
  19568. X
  19569. X  while (!feof (f) && !done && i < MAX_LINE) {
  19570. X    pc = c;
  19571. X    c = fgetc (f);
  19572. X    (c == '`' || c == '*' || c == '?' || c == '|' ? invalid_char = TRUE : 0);
  19573. X/*
  19574. X    (c == '/' && (pc == EOS || pc == ';') ? invalid_char = TRUE : 0);
  19575. X*/
  19576. X    (c == '\'' ? (nsquote = 1) : 0);
  19577. X    (c == '\"' ? (pc != '\\' ? (ndquote = !ndquote) : 0) : 0);
  19578. X    (c == '(' ? (!ndquote ? ++nparen : 0) : 0);
  19579. X    (c == ')' ? (!ndquote ? --nparen : 0) : 0);
  19580. X    (c == '<' ? (!ndquote ? ++nangle : 0) : 0);
  19581. X    (c == '>' ? (!ndquote ? --nangle : 0) : 0);
  19582. X    (c == '[' ? (!ndquote ? ++nsquare : 0): 0);
  19583. X    (c == ']' ? (!ndquote ? --nsquare : 0) : 0);
  19584. X    (isspace (c) ?
  19585. X     ((!aliases_file && (ndquote || nparen || nangle || nsquare)) ? 0 
  19586. X      : (done = TRUE)) : 0);
  19587. X    subscriber [i++] = c;
  19588. X  }
  19589. X  if (i > 0)
  19590. X    subscriber [i - 1] = EOS;
  19591. X  if (!aliases_file &&
  19592. X      (nsquote || ndquote || nparen || nangle || nsquare || invalid_char))
  19593. X    return FALSE;    /* Error in address */
  19594. X  return TRUE;
  19595. X}
  19596. X
  19597. X/*
  19598. X  Extract the originator of the message, i.e. the list that the original
  19599. X  message first originated from.
  19600. X*/
  19601. X
  19602. Xvoid extract_origin (char *s)
  19603. X{
  19604. X  char *p;
  19605. X
  19606. X  if (p = strchr (s, '<'))
  19607. X    sprintf (s, "%s", p + 1); /* Remove '<' */
  19608. X  if (p = strchr (s, '>'))
  19609. X    *p = EOS;  /* Remove '>' */
  19610. X  else {  /* Get to the end of the address */
  19611. X    while (*s != EOS && !isspace (*s))
  19612. X      ++s;
  19613. X    *s = EOS;
  19614. X  }
  19615. X}
  19616. X
  19617. X/*
  19618. X  Given an RFC 822 From: line address, strip comments etc. and extract
  19619. X  the actual address.
  19620. X*/
  19621. X
  19622. Xvoid extract_address (char *s)
  19623. X{
  19624. X  char *p;
  19625. X
  19626. X  if (p = strchr (s, '<'))
  19627. X    sprintf (s, "%s", p + 1); /* Remove '<' */
  19628. X  if (*s == '|' || *s == ':')
  19629. X    *s = EOS;  /* Protect against trojans */
  19630. X  if (p = strchr (s, '>'))
  19631. X    *p = EOS;  /* Remove '>' */
  19632. X  if (p = strchr (s, '('))
  19633. X    *p = EOS; /* Remove comments */
  19634. X  while (*s != EOS && !isspace (*s)) /* Get to the end of the address */
  19635. X    ++s;
  19636. X  *s = EOS;
  19637. X}
  19638. X
  19639. X/*
  19640. X  Scan 's' and escape the following characters:
  19641. X  ( ) [ ] < > { } \ : ; ' ` . ^ $ *
  19642. X*/
  19643. X
  19644. Xvoid escape_address (char *s)
  19645. X{
  19646. X  char *r;
  19647. X
  19648. X  while (*s != EOS) {
  19649. X    switch (*s) {
  19650. X    case '(': case ')': case '[': case ']': case '<': case '>': case '\\':
  19651. X    case ':': case ';': case '\'': case '`': case '.': case '^':
  19652. X    case '$': case '*': case '{': case '}':
  19653. X      r = s + strlen (s);    /* Start from the end */
  19654. X      while (r != s)
  19655. X        *(r + 1) = *r,
  19656. X    --r;
  19657. X      *(r + 1) = *r;
  19658. X      *r = '\\';
  19659. X      ++s;
  19660. X      break;
  19661. X    }
  19662. X    ++s;
  19663. X  }
  19664. X}
  19665. *-*-END-of-src/sender.c-*-*
  19666. echo x - src/serverd.c
  19667. sed 's/^X//' >src/serverd.c <<'*-*-END-of-src/serverd.c-*-*'
  19668. X/*
  19669. X  ----------------------------------------------------------------------------
  19670. X  |                       LISTPROCESSOR SYSTEM DAEMON                 |
  19671. X  |                                                                          |
  19672. X  |                               Version 5.1                                |
  19673. X  |                                                                          |
  19674. X  |                (or, when Computer Science gets to you)                   |
  19675. X  |                                                                          |
  19676. X  |                    Written by Anastasios Kotsikonas                      |
  19677. X  |                           (tasos@cs.bu.edu)                              |
  19678. X  |                                                                          |
  19679. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  19680. X  | whole and not in parts, as long as you do not remove or alter the author |
  19681. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  19682. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  19683. X  | provided for your personal use, you may not alter the functions          |
  19684. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  19685. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  19686. X  | any changes you may have made. No part of the source code bearing a         |
  19687. X  | copyright notice can be included in commercial software systems without  |
  19688. X  | written permission by the author.                         |
  19689. X  | By using this software you are bound by this agreement.             |
  19690. X  | This software comes with no warranties and cannot be sold for profit.    |
  19691. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  19692. X  | files when distributing this software.                                   |
  19693. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  19694. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  19695. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  19696. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  19697. X  | (ii).                                                                    |
  19698. X  |                                                                          |
  19699. X  | Enhanced by: Warren Burstein.                                            |
  19700. X  ----------------------------------------------------------------------------
  19701. X
  19702. X  Spawn list or listproc upon arrival of new messages. Send mail to
  19703. X  MANAGER if something went wrong (only if using UCB mail).
  19704. X  serverd will not spawn if the current load average is above max_load
  19705. X  and the -l flag is on, until it has delayed MAX_TRIES * 30 seconds.
  19706. X  serverd communicates with listerv via exit statuses 6 and 7; these are
  19707. X  the requests to shutdown/restart the system; on status 7, serverd spawns
  19708. X  start and dies; if it cannot restart, it sends mail and commits suicide.
  19709. X  serverd reports to REPORT_SERVERD.
  19710. X
  19711. X  The server may also run in interactive mode and listen for TCP connections
  19712. X  at a specified port. Users are able of entering requests and getting replies
  19713. X  live. For this, a separate listener process is spawned which accepts or
  19714. X  rejects the connections, then it in turn forks off children to handle
  19715. X  accepted connections.
  19716. X
  19717. X        Master process    (looks for email requests/messages)
  19718. X               |
  19719. X            Listener    (accepts or rejects connection requests)
  19720. X               |
  19721. X              /|\
  19722. X            children    (process live requests)
  19723. X
  19724. X  If the Master process dies in any way but a SIGKILL signal, then all
  19725. X  processes abort. If the Listener process dies (including a SIGKILL signal),
  19726. X  all processes abort as well. If the Master is killed with SIGKILL, behavior
  19727. X  will be undefined and a semaphore will be left unused in the system (use
  19728. X  ipcrm to remove it). If any of the children die abnormally (including a
  19729. X  SIGKILL signal) the Listener process will report to that effect; however,
  19730. X  the connection will remain "open" on the other end until it times out
  19731. X  locally.
  19732. X
  19733. X  A "restart" or "shutdown" request (live or not) will kill all processes and
  19734. X  in the case of "restart", a new Master and Listener will be created.
  19735. X
  19736. X  Synchronization between all processes is done via a semaphore. Removing or
  19737. X  altering the semaphore while the system is running will bring the system
  19738. X  down.
  19739. X
  19740. X  COMMAND LINE OPTIONS:
  19741. X    -1: Execute only once -- to be used with cron.
  19742. X    -l: Enforce restrictions based on the current load average.
  19743. X    -e: Echo reports to the screen.
  19744. X    -i: Interactive server; it listens for tcp connections. The argument
  19745. X    that follows is the maximum duration (in seconds) of each connection.
  19746. X
  19747. X  EXIT CODES:
  19748. X    0: OK
  19749. X    1: Could not open or lock file
  19750. X    2: SIGINT signal
  19751. X    3: Command line option error
  19752. X    4: Syntax error in file
  19753. X    5: Could not spawn
  19754. X    6: Shutdown request
  19755. X    7: Restart request
  19756. X    8: Received system signal
  19757. X    9: Too many multiple recipients
  19758. X   10: Could not deliver mail
  19759. X   11: Malloc failed
  19760. X   12: Cannot fork
  19761. X   13: Socket connection problem
  19762. X   14: Semaphore error
  19763. X   15: Cannot setuid, setgid
  19764. X   16: Internal error
  19765. X
  19766. X*/
  19767. X
  19768. X#include <stdio.h>
  19769. X#ifdef SYSLOG
  19770. X# ifdef ultrix
  19771. X#  include <sys/syslog.h>
  19772. X# else
  19773. X#  include <syslog.h>
  19774. X# endif
  19775. X#endif
  19776. X#ifndef unknown_port
  19777. X# ifndef __NeXT__
  19778. X#  include <unistd.h>
  19779. X# else
  19780. X#  include <libc.h>
  19781. X# endif
  19782. X#endif
  19783. X#include <sys/types.h>
  19784. X#if defined (stardent) || defined (stellar) || defined (titan)
  19785. X# include <rpc/types.h>
  19786. X#endif
  19787. X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
  19788. X && !defined (sequent) && !defined (unknown_port)
  19789. X# include <malloc.h>
  19790. X#endif
  19791. X#include <sys/stat.h>
  19792. X#include <signal.h>
  19793. X#include <fcntl.h>
  19794. X#include <time.h>
  19795. X#include <ctype.h>
  19796. X#include <string.h>
  19797. X#include <errno.h>
  19798. X#ifdef unknown_port
  19799. Xextern int errno;
  19800. X#endif
  19801. X#include <math.h>
  19802. X#include <sys/wait.h>
  19803. X#if !defined (sequent) && !defined (__NeXT__) && !defined (__convex__) && \
  19804. X !defined (apollo) && !defined (i386) && !defined (unknown_port)
  19805. X# include <sys/termio.h>
  19806. X#endif
  19807. X#ifndef sun
  19808. X# include <sys/ioctl.h>
  19809. X#endif
  19810. X#include "defs.h"
  19811. X#include "serverd.h"
  19812. X#include "struct.h"
  19813. X#include "global.h"
  19814. X#if defined (__NeXT__) || defined (unknown_port)
  19815. X# include "next.h"
  19816. X#endif
  19817. X
  19818. X#ifdef GO_INTERACTIVE
  19819. X# include <sys/socket.h>
  19820. X# ifndef stellar
  19821. X#  include <sys/time.h>
  19822. X# endif
  19823. X# include <netinet/in.h>
  19824. X# include <netdb.h>
  19825. X# include <sys/ipc.h>
  19826. X# include <sys/sem.h>
  19827. X# include <pwd.h>
  19828. X#endif
  19829. X
  19830. X#ifdef __STDC__
  19831. X# include <stdarg.h>
  19832. Xextern int  syscom (char *, ...);
  19833. Xextern char *tsprintf (char *, ...);
  19834. X#else
  19835. X# include <varargs.h>
  19836. Xextern int  syscom ();
  19837. Xextern char *tsprintf ();
  19838. X#endif
  19839. X
  19840. X#if !defined (__NeXT__) && !defined (__osf__) && !defined (_AIX)
  19841. Xextern double atof ();
  19842. Xextern long int atoi (char *);
  19843. X#else
  19844. Xextern int atoi (const char *);
  19845. X#endif
  19846. Xextern int  sys_config (FILE *, SYS *);
  19847. Xextern int  _getopt (int, char **, char *);
  19848. Xextern void setup_string (char *, char *, char *);
  19849. Xextern void init_signals (void);
  19850. Xextern void catch_signals (void);
  19851. Xextern void report_progress (FILE *, char *, int);
  19852. Xextern int  lock_file (char *, int, int, BOOLEAN);
  19853. Xextern void unlock_file (int);
  19854. Xextern void clean_request (char *);
  19855. Xextern char *upcase (char *);
  19856. Xextern BOOLEAN owner_listed (char *, char *, char *, FILE *);
  19857. Xextern BOOLEAN host_listed (char *, char *, FILE *);
  19858. Xextern BOOLEAN subscribed (FILE *, char *, char *, char *, char *, char *,
  19859. X               BOOLEAN);
  19860. Xextern int long write_to_fd (int, char *, long int);
  19861. Xextern int otoi (char *);
  19862. Xextern char *_strstr (char *, char *);
  19863. Xextern void my_abort (int);
  19864. Xextern int echo (char *, char *);
  19865. Xextern int cat_append (char *, char *);
  19866. Xextern int re_strcmp (char *, char *, char *);
  19867. Xextern int insert_word (char *, char **, int, int, int);
  19868. Xextern char *mystrdup (char *);
  19869. Xextern int semtran (int);
  19870. Xextern void semremove (int);
  19871. Xextern int prevch (char *, char *);
  19872. Xextern int nextch (char *);
  19873. X
  19874. X
  19875. Xvoid   main (int, char **, char **);
  19876. Xvoid   serverd_config (void);
  19877. Xvoid   usage (void);
  19878. Xint    gexit (int);
  19879. Xvoid   load_wait (float);
  19880. Xvoid   run_program (char *, BOOLEAN, int);
  19881. X#ifdef GO_INTERACTIVE
  19882. Xvoid   sighandle (int);
  19883. Xvoid   listener_exited (void);
  19884. Xvoid   close_connection (int);
  19885. Xint    check_timeout (CLIENT []);
  19886. Xint    create_connection (void);
  19887. Xvoid   process_live_request (int, struct sockaddr_in);
  19888. XBOOLEAN check_for_redirection (char *, char *, int *, int, BOOLEAN);
  19889. XBOOLEAN writeable_file (char *, int);
  19890. XBOOLEAN child_alive (int, CLIENT []);
  19891. XBOOLEAN still_delivering_mail (int);
  19892. X#endif
  19893. X
  19894. X
  19895. Xvoid main (int argc, char **argv, char **envp)
  19896. X{
  19897. X  struct stat stat_buf;
  19898. X  int rlfd = 2;
  19899. X  FILE *f, *fp;
  19900. X  float max_load;
  19901. X  BOOLEAN loadr = FALSE, execute_once = FALSE, already_aborted;
  19902. X  char list [MAX_LINE];
  19903. X  char server [MAX_LINE], fulldate [MAX_LINE];
  19904. X  char msg [4096];
  19905. X  char *mask, *ch;
  19906. X  int c;
  19907. X#ifdef GO_INTERACTIVE
  19908. X  char *options = "1l:i:e", *s, reply [MAX_LINE], version [MAX_LINE];
  19909. X  char welcome [65536];
  19910. X  int connid = 0, port, l, pid, _nforks;
  19911. X  struct sockaddr_in client;
  19912. X  struct hostent *hp;
  19913. X  union semun {
  19914. X    int val;
  19915. X    struct semid_ds *buf;
  19916. X    ushort *array;
  19917. X  } sembuf;
  19918. X  int smask;
  19919. X#else
  19920. X  char *options = "1l:e";
  19921. X#endif
  19922. X#ifdef ultrix
  19923. X  time_t time_is = 0;
  19924. X#else
  19925. X  long int time_is = 0;
  19926. X#endif
  19927. X  long int current_date = -1, new_date, time_then = 0;
  19928. X  struct tm *t;
  19929. X  extern char *optarg, *getenv();
  19930. X  extern int optopt;
  19931. X  int i, j, current_list;
  19932. X
  19933. X  prog = argv[0];
  19934. X  while ((c = _getopt (argc, argv, options)) != EOF)
  19935. X    switch ((char) c) {
  19936. X      case '1': execute_once = TRUE; break;
  19937. X      case 'e': tty_echo = TRUE; break;
  19938. X      case 'l': loadr = TRUE; 
  19939. X        max_load = (float) atof (optarg); 
  19940. X        break;
  19941. X#ifdef GO_INTERACTIVE
  19942. X      case 'i':
  19943. X    interactive = TRUE;
  19944. X    if ((conn_duration = atoi (optarg)) <= 0)
  19945. X      fprintf (stderr, "-i %d ???\n", conn_duration),
  19946. X      exit (3);
  19947. X    break;
  19948. X#endif
  19949. X      case ':': 
  19950. X        fprintf (stderr, "serverd:  Option '%c' requires an argument.\n",
  19951. X         optopt);
  19952. X    exit (3);
  19953. X      case '?':
  19954. X      default:
  19955. X    usage ();
  19956. X    }
  19957. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  19958. X    umask (otoi (mask));
  19959. X  else
  19960. X    mask = "066",
  19961. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  19962. X#ifndef NO_LOCKS
  19963. X  if ((lfd = lock_file (SERVERD_LOCK_FILE, O_RDWR, 0, FALSE)) < 0)
  19964. X    fprintf (stderr, "serverd: Unable to lock %s. Aborting.\n", 
  19965. X             SERVERD_LOCK_FILE),
  19966. X    exit (2);
  19967. X#endif
  19968. X#ifdef SYSLOG
  19969. X  openlog ("ListProcessor: serverd", LOG_NDELAY
  19970. X# ifndef i386
  19971. X       |LOG_NOWAIT
  19972. X# endif
  19973. X       , SYSLOG);
  19974. X# ifndef ultrix
  19975. X  setlogmask (LOG_UPTO (LOG_INFO));
  19976. X# endif
  19977. X#else
  19978. X  if ((report = fopen (REPORT_SERVERD, "a")) == NULL)
  19979. X    fprintf (stderr, "serverd: Could not open %s\n", REPORT_SERVERD),
  19980. X    exit (1);
  19981. X  chmod (REPORT_SERVERD, 384);
  19982. X  fprintf (report, "%s", COPYRIGHT);
  19983. X  fflush (report);
  19984. X#endif
  19985. X
  19986. X#ifdef GO_INTERACTIVE
  19987. X  if ((pwentry = getpwuid (getuid ())) == NULL)
  19988. X    report_progress (report, "main(): Invalid user account", TRUE),
  19989. X    exit (3);
  19990. X# ifndef SYSLOG
  19991. X  if (chown (REPORT_SERVERD, pwentry->pw_uid, pwentry->pw_gid))
  19992. X    report_progress (report, "\nmain(): Cannot chown()", TRUE),
  19993. X    exit (15);
  19994. X# endif
  19995. X#endif
  19996. X  if ((f = fopen (PID_SERVERD, "w")) != NULL)
  19997. X    fprintf (f, "%d", getpid()),
  19998. X    fclose (f)
  19999. X#ifdef GO_INTERACTIVE
  20000. X    ,chown (PID_SERVERD, pwentry->pw_uid, pwentry->pw_gid);
  20001. X#else
  20002. X    ;
  20003. X#endif
  20004. X
  20005. X  signal (SIGINT, (void (*)()) gexit);
  20006. X#ifdef GO_INTERACTIVE
  20007. X# if defined (bsd)
  20008. X  sigsetmask (0);
  20009. X# elif defined (svr3) || defined (svr4)
  20010. X#  ifdef SIGCLD
  20011. X  sigrelse (SIGCLD);
  20012. X#  else
  20013. X  sigrelse (SIGCHLD);
  20014. X#  endif
  20015. X# endif
  20016. X# ifdef SIGCLD
  20017. X  signal (SIGCLD, (void (*)()) sighandle);
  20018. X# else
  20019. X  signal (SIGCHLD, (void (*)()) sighandle);
  20020. X# endif
  20021. X  signal (ABORT_SIG, (void (*)()) listener_exited);
  20022. X#endif
  20023. X  init_signals();
  20024. X  catch_signals ();
  20025. X
  20026. X  time (&time_is);
  20027. X
  20028. X  nlists = sys_config (report, &sys);
  20029. X  if (sys.fax.prog[0] == EOS)
  20030. X    strcat (sys.server.cmdoptions, " -d fax");
  20031. X
  20032. X  if (!tty_echo) {
  20033. X    j = -1;
  20034. X#if defined (TIOCNOTTY) && defined (SIGTTOU) && defined (SIGTTIN)
  20035. X    if ((i = open ("/dev/tty", 2)) >= 0)
  20036. X      j = ioctl (i, TIOCNOTTY, 0),
  20037. X      close (i);
  20038. X#endif
  20039. X    if (j < 0 && 
  20040. X#ifdef svr4
  20041. X    setsid ()
  20042. X#else
  20043. X# ifdef SETPGRP_NEEDS_ARGS
  20044. X    setpgrp (0, 0) 
  20045. X# else
  20046. X    setpgrp ()
  20047. X# endif
  20048. X#endif 
  20049. X    < 0)
  20050. X      report_progress (report, "WARNING: could not detach from tty", TRUE);
  20051. X  }
  20052. X
  20053. X  ppid = getpid ();
  20054. X#ifdef GO_INTERACTIVE
  20055. X  if (interactive) { /* Spawn Listener process */
  20056. X    if ((sid = semtran (0)) < 0)    /* Get semaphore id */
  20057. X      report_progress (report, tsprintf ("\nmain(): semget() failed; errno %d",
  20058. X                     errno), TRUE),
  20059. X      exit (14);
  20060. X    if ((sembuf.buf = (struct semid_ds *) malloc (sizeof (struct semid_ds))) ==
  20061. X    NULL)
  20062. X      report_progress (report, "\nmain(): malloc() failed", TRUE),
  20063. X      exit (11);
  20064. X    sembuf.buf->sem_perm.uid = pwentry->pw_uid;
  20065. X    sembuf.buf->sem_perm.gid = pwentry->pw_gid;
  20066. X    sembuf.buf->sem_perm.mode = 0600;
  20067. X    if (semctl (sid, 1, IPC_SET, sembuf)) /* Change owner to server */
  20068. X      report_progress (report, tsprintf ("\nmain(): semctl() failed; errno %d",
  20069. X                     errno), TRUE),
  20070. X      exit (14);
  20071. X    free ((struct semid_ds *) sembuf.buf);
  20072. X
  20073. X    if (getuid () & geteuid ())
  20074. X      report_progress (report, "WARNING: serverd not started with root \
  20075. Xprivileges", TRUE);
  20076. X    if ((chpid = fork()) < 0)
  20077. X      report_progress (report, "\nmain(): Master process cannot fork Listener \
  20078. Xprocess", TRUE),
  20079. X      exit (12);
  20080. X    else if (chpid == 0) { /* Child process */
  20081. X      chpid = getpid ();   /* Set for signal handling purposes */
  20082. X      signal (SIGINT, (void (*)()) sighandle);
  20083. X# ifdef SIGCLD
  20084. X      signal (SIGCLD, (void (*)()) sighandle);
  20085. X# else
  20086. X      signal (SIGCHLD, (void (*)()) sighandle);
  20087. X# endif
  20088. X      signal (SIGTERM, (void (*)()) sighandle);
  20089. X      signal (SIGSEGV, (void (*)()) sighandle);
  20090. X      signal (SIGILL, (void (*)()) sighandle);
  20091. X      signal (SIGQUIT, (void (*)()) sighandle);
  20092. X      signal (SIGBUS, (void (*)()) sighandle);
  20093. X      strcpy (version, VERSION);
  20094. X      ch = strchr (version, ' ');
  20095. X      *ch = EOS;
  20096. X
  20097. X      if ((sock_fd = create_connection ()) < 0)
  20098. X    report_progress (report, "\nmain(): Listener process cannot create \
  20099. Xconnection", TRUE),
  20100. X    kill (ppid, ABORT_SIG),
  20101. X    exit (13);
  20102. X      if (setuid (pwentry->pw_uid) || setgid (pwentry->pw_gid))
  20103. X    report_progress (report, "\nmain(): Listener process cannot \
  20104. Xsetuid()/setgid()", TRUE),
  20105. X    kill (ppid, ABORT_SIG),
  20106. X    exit (15);
  20107. X      while (007) { /* Listen for ever */
  20108. X
  20109. X    l = sizeof (client);
  20110. X    if ((msg_sock = accept (sock_fd, (struct sockaddr *) &client,
  20111. X                (int *) &l)) < 0) {
  20112. X      if (errno != EINTR
  20113. X#ifdef ERESTART
  20114. X          && errno != ERESTART
  20115. X#endif
  20116. X          )
  20117. X        report_progress (report, "\nmain(): Listener process cannot accept()",
  20118. X                 TRUE),
  20119. X        kill (ppid, ABORT_SIG),
  20120. X        exit (13);
  20121. X      continue;
  20122. X    }
  20123. X    else { /* New client; see if we can handle it */
  20124. X      hp = gethostbyaddr ((char *) &client.sin_addr,
  20125. X                  sizeof (struct in_addr), client.sin_family);
  20126. X      report_progress (report,
  20127. X               tsprintf ("Connection request from %s: ",
  20128. X                     upcase ((s = (hp ? hp->h_name :
  20129. X                           (char *) inet_ntoa (client.sin_addr))))),
  20130. X               FALSE);
  20131. X      if (!stat (PRIVILEGED_HOSTSF, &stat_buf))
  20132. X        if (!host_listed (PRIVILEGED_HOSTSF, s, report)) {
  20133. X          CANNOT_CONNECT ("not a privileged host", CONN_ABORTED,
  20134. X                  "Not a privileged host.\n");
  20135. X          continue;
  20136. X        }
  20137. X      if (host_listed (UNWANTED_HOSTSF, s, report)) {
  20138. X        CANNOT_CONNECT ("unwanted host", CONN_ABORTED,
  20139. X                "Not a privileged host.\n");
  20140. X        continue;
  20141. X      }
  20142. X
  20143. X      if (nforks < 0 || nforks > MAX_CONNECTIONS)
  20144. X        report_progress (report, tsprintf ("\nmain(): Listener process: \
  20145. Xinternal error: nforks=%d", nforks), TRUE),
  20146. X        kill (ppid, ABORT_SIG),
  20147. X        exit (16);
  20148. X      if (nforks + 1 > MAX_CONNECTIONS) { /* Too many connections */
  20149. X        if ((pid = check_timeout (clients)) > 0) {
  20150. X          kill (pid, TIMEOUT_SIG);    /* Tell it to commit suicide */
  20151. X          while (child_alive (pid, clients)); /* Wait */
  20152. X        }
  20153. X        else { /* No children have timed out, so tough */
  20154. X          CANNOT_CONNECT ("refused", SERVER_BUSY, SERVER_BUSY_);
  20155. X          continue;
  20156. X        }
  20157. X      }
  20158. X      report_progress (report, tsprintf ("connected (client #%d)", connid),
  20159. X               TRUE);
  20160. X      /* Parent increments the number of times it has forked */
  20161. X      _nforks = nforks;
  20162. X      clients [nforks].time = time (0); /* Save time child spawned */
  20163. X      clients [nforks].connid = connid++;
  20164. X      strcpy (clients [nforks++].name,
  20165. X          (hp ? hp->h_name : (char *) inet_ntoa (client.sin_addr)));
  20166. X# if defined (bsd)
  20167. X#  ifdef SIGCLD
  20168. X      smask = sigblock (sigmask (SIGCLD));
  20169. X#  else
  20170. X      smask = sigblock (sigmask (SIGCHLD));
  20171. X#  endif
  20172. X# elif defined (svr4) || defined (svr3)
  20173. X#  ifdef SIGCLD
  20174. X      sighold (SIGCLD);
  20175. X#  else
  20176. X      sighold (SIGCHLD);
  20177. X#  endif
  20178. X# endif
  20179. X      if ((pid = fork ()) < 0) {    /* fork */
  20180. X        CANNOT_CONNECT ("cannot fork", SYS_ERROR, "Remote system error.\n");
  20181. X# if defined (bsd)
  20182. X        sigsetmask (smask);
  20183. X# elif defined (svr3) || defined (svr4)
  20184. X#  ifdef SIGCLD
  20185. X        sigrelse (SIGCLD);
  20186. X#  else
  20187. X        sigrelse (SIGCHLD);
  20188. X#  endif
  20189. X# endif
  20190. X        continue;
  20191. X      }
  20192. X      else if (pid == 0) {        /* Child process */
  20193. X        close (sock_fd);    /* Close unused parent socket */
  20194. X# ifdef SIGCLD
  20195. X        signal (SIGCLD, SIG_DFL);
  20196. X# else
  20197. X        signal (SIGCHLD, SIG_DFL);
  20198. X# endif
  20199. X        signal (TIMEOUT_SIG, (void (*)()) close_connection);
  20200. X        signal (ABORT_SIG, (void (*)()) close_connection);
  20201. X        signal (SIGALRM, (void (*)()) close_connection);
  20202. X        signal (SIGPIPE, (void (*)()) close_connection);
  20203. X        signal (SIGINT, (void (*)()) SIG_IGN);
  20204. X        signal (SIGTERM, (void (*)()) close_connection);
  20205. X        signal (SIGSEGV, (void (*)()) close_connection);
  20206. X        signal (SIGILL, (void (*)()) close_connection);
  20207. X        signal (SIGQUIT, (void (*)()) close_connection);
  20208. X        signal (SIGBUS, (void (*)()) close_connection);
  20209. X        alarm (conn_duration);
  20210. X        time_is = time (0);
  20211. X        sprintf (welcome, "%s interactive ListProcessor.\nVersion %s %s\
  20212. XMaximum connection duration is %d seconds.\n",
  20213. X             sys.organization, version, ctime (&time_is),
  20214. X             conn_duration);
  20215. X        if ((f = fopen (WELCOMEF, "r"))) {
  20216. X          while (!feof (f))
  20217. X        fgets (welcome + strlen (welcome), MAX_LINE, f);
  20218. X          fclose (f);
  20219. X        }
  20220. X        sprintf (msg, "%d %d %s %d %d\n%d %d \n\n%s", CONNECT,
  20221. X                       conn_duration, version, strlen (PROMPT),
  20222. X                       strlen (CONT_PROMPT), OK,
  20223. X                       strlen (welcome) +
  20224. X                       strlen (LOGIN) + 1, welcome);
  20225. X        if (write_to_fd (msg_sock, msg, strlen (msg)) < 0)
  20226. X          CLIENT_LOST (13);
  20227. X        process_live_request (msg_sock, client);
  20228. X      }
  20229. X      else
  20230. X        clients [_nforks].pid = pid,
  20231. X# if defined (bsd)
  20232. X        sigsetmask (smask),
  20233. X# elif defined (svr3) || defined (svr4)
  20234. X#  ifdef SIGCLD
  20235. X        sigrelse (SIGCLD),
  20236. X#  else
  20237. X        sigrelse (SIGCHLD),
  20238. X#  endif
  20239. X# endif
  20240. X        close (msg_sock);
  20241. X    }
  20242. X      }
  20243. X    }
  20244. X  }
  20245. X#endif
  20246. X
  20247. X#ifdef GO_INTERACTIVE
  20248. X  if (setuid (pwentry->pw_uid) || setgid (pwentry->pw_gid))
  20249. X    report_progress (report, "\nmain(): Master process cannot \
  20250. Xsetuid()/setgid()", TRUE),
  20251. X    gexit (15);
  20252. X#endif
  20253. X
  20254. X  serverd_config ();
  20255. X  current_list = -1;
  20256. X  while (007) {
  20257. X
  20258. X    if ((++current_list) == nlists)
  20259. X      current_list = 0;
  20260. X
  20261. X    if (!stat (lists[current_list].list_mail_f, &stat_buf) &&
  20262. X    stat_buf.st_size > 0 &&
  20263. X    (rlfd = lock_file (lists[current_list].list_mail_f, O_RDWR, 0, FALSE)) >= 0) {
  20264. X      unlock_file (rlfd);
  20265. X
  20266. X      if (sys.lists[current_list].max_messages) {
  20267. X    time (&time_is);
  20268. X    t = localtime (&time_is);
  20269. X    new_date = t->tm_mon + 1 + t->tm_mday + t->tm_year;
  20270. X    if (new_date != lists[current_list].current_date)
  20271. X      lists[current_list].nmessages = 0,
  20272. X      lists[current_list].done_for_the_day = FALSE,
  20273. X      lists[current_list].current_date = new_date,
  20274. X      echo (tsprintf ("0 %d %d %d", t->tm_mon + 1, t->tm_mday,
  20275. X              t->tm_year),
  20276. X        lists[current_list].list_limitsf);
  20277. X    if (!lists[current_list].done_for_the_day) {
  20278. X      if ((f = fopen (lists[current_list].list_limitsf, "r"))) {
  20279. X        fscanf (f, "%d", &lists[current_list].nmessages);
  20280. X        fclose (f);
  20281. X      }
  20282. X      if (lists[current_list].nmessages >= sys.lists[current_list].max_messages) {
  20283. X        lists[current_list].done_for_the_day = TRUE;
  20284. X        lists[current_list].nmessages = 0;
  20285. X        goto xxx;
  20286. X      }
  20287. X    }
  20288. X    else
  20289. X      goto xxx;
  20290. X      }
  20291. X
  20292. X      time_is = time (0);
  20293. X      sprintf (fulldate, "%s", ctime (&time_is));
  20294. X      if ((ch = strchr (fulldate, '\n')))
  20295. X    *ch = EOS;
  20296. X      report_progress (report, tsprintf ("\n--- NEW MAIL FOR %s on %s ---\n",
  20297. X                     sys.lists[current_list].alias,
  20298. X                     fulldate), FALSE);
  20299. X
  20300. X      if (loadr) /* enforce restrictions */
  20301. X    load_wait (max_load);
  20302. X
  20303. X      RESET (list);
  20304. X      sprintf (list, "%s %s %s", LIST, sys.lists[current_list].alias,
  20305. X           sys.lists[current_list].cmdoptions);
  20306. X#ifdef GO_INTERACTIVE
  20307. X      if (interactive)
  20308. X    sprintf (list + strlen (list), " -S %d", sid);
  20309. X#endif
  20310. X      run_program (list, FALSE, -1);
  20311. X     xxx: ;
  20312. X    }
  20313. X/*
  20314. X    if (sys.frequency > 0)
  20315. X      sleep (sys.frequency);     do a quickie to The Spy Who Loved Him
  20316. X*/
  20317. X    if (!stat (lists[current_list].digest_msgf, &stat_buf) && stat_buf.st_size > 0) {
  20318. X      /*
  20319. X     Something in the digest message file, see how long it's been
  20320. X     since last message was sent by reading digest_timef.
  20321. X      */
  20322. X      if (fp = fopen (lists[current_list].digest_timef, "r"))
  20323. X    fscanf (fp, "%ld\n", &time_then),
  20324. X    fclose (fp);
  20325. X      if ((time(0) - time_then) / 3600 >= sys.lists[current_list].digest_hours) {
  20326. X    report_progress (report,
  20327. X             tsprintf ("\n--- DIGEST TIME REACHED FOR %s ---\n",
  20328. X                   sys.lists[current_list].alias), FALSE);
  20329. X
  20330. X        if (loadr)
  20331. X      load_wait (max_load);
  20332. X
  20333. X        RESET (list);
  20334. X        sprintf (list, "%s %s %s -d", LIST, sys.lists[current_list].alias,
  20335. X             sys.lists[current_list].cmdoptions);
  20336. X#ifdef GO_INTERACTIVE
  20337. X    if (interactive)
  20338. X      sprintf (list + strlen (list), " -S %d", sid);
  20339. X#endif
  20340. X        run_program (list, FALSE, -1);
  20341. X      }
  20342. X    }
  20343. X
  20344. X    if (!stat (BATCH_FILE, &stat_buf) && stat_buf.st_size > 0) {
  20345. X      time (&time_is);
  20346. X      t = localtime (&time_is);
  20347. X      new_date = t->tm_mon + 1 + t->tm_mday + t->tm_year;
  20348. X      if (new_date != current_date) { /* Process batch on new day only */
  20349. X    current_date = new_date; /* New day or first time through loop */
  20350. X    report_progress (report, "\n--- PROCESSING THE BATCH QUEUE ---\n",
  20351. X             FALSE);
  20352. X    RESET (server);
  20353. X    sprintf (server, "%s %s -B", SERVER, sys.server.cmdoptions);
  20354. X#ifdef GO_INTERACTIVE
  20355. X    if (interactive)
  20356. X      sprintf (server + strlen (server), " -S %d", sid);
  20357. X#endif
  20358. X    run_program (server, TRUE, -1);
  20359. X      }
  20360. X    }
  20361. X
  20362. X    if (!stat (SERVER_MAIL_FILE, &stat_buf) && stat_buf.st_size > 0 &&
  20363. X    (rlfd = lock_file (SERVER_MAIL_FILE, O_RDWR, 0, FALSE)) >= 0) {
  20364. X      unlock_file (rlfd);
  20365. X
  20366. X      time (&time_is);
  20367. X      t = localtime (&time_is);
  20368. X      new_date = t->tm_mon + 1 + t->tm_mday + t->tm_year;
  20369. X      current_date = new_date; /* New day or first time through loop */
  20370. X      time_is = time (0);
  20371. X      sprintf (fulldate, "%s", ctime (&time_is));
  20372. X      if ((ch = strchr (fulldate, '\n')))
  20373. X        *ch = EOS;
  20374. X      report_progress (report,
  20375. X    tsprintf ("\n--- NEW MAIL FOR SERVER on %s ---\n", fulldate), FALSE);
  20376. X
  20377. X      if (loadr) /* Enforce restrictions */
  20378. X    load_wait (max_load);
  20379. X
  20380. X      RESET (server);
  20381. X      sprintf (server, "%s %s", SERVER, sys.server.cmdoptions);
  20382. X#ifdef GO_INTERACTIVE
  20383. X      if (interactive)
  20384. X    sprintf (server + strlen (server), " -S %d", sid);
  20385. X#endif
  20386. X      run_program (server, TRUE, -1);
  20387. X    }
  20388. X
  20389. X    if (execute_once && current_list == 0)
  20390. X      gexit (0);
  20391. X    if (sys.frequency > 0)
  20392. X      sleep (sys.frequency);     /* do a quickie to Money Penny */
  20393. X  }
  20394. X}
  20395. X
  20396. Xvoid serverd_config ()
  20397. X{
  20398. X  int i, mon, day, year;
  20399. X  FILE *f;
  20400. X
  20401. X  for (i = 0; i < nlists; ++i) {
  20402. X    setup_string (lists[i].list_mail_f, sys.lists[i].alias, LIST_MAIL_FILE);
  20403. X    setup_string (lists[i].digest_msgf, sys.lists[i].alias, DIGEST_MSG);
  20404. X    setup_string (lists[i].digest_timef, sys.lists[i].alias, DIGEST_TIME);
  20405. X    setup_string (lists[i].list_limitsf, sys.lists[i].alias, LIST_LIMITS);
  20406. X    lists[i].nmessages = mon = day = year = 0;
  20407. X    lists[i].done_for_the_day = FALSE;
  20408. X    if ((f = fopen (lists[i].list_limitsf, "r")))
  20409. X      fscanf (f, "%d %d %d %d", &lists[i].nmessages, &mon, &day, &year),
  20410. X      fclose (f);
  20411. X    lists[i].current_date = mon + day + year;
  20412. X  }
  20413. X}
  20414. X
  20415. Xvoid usage ()
  20416. X{
  20417. X#ifdef GO_INTERACTIVE
  20418. X  fprintf (stderr, "Usage: serverd [-1] [-e] [-l load] [-i duration]\n\
  20419. X-1: Execute only once.\n\
  20420. X-e: Echo reports to the screen.\n\
  20421. X-l: Enforce load restrictions.\n\
  20422. X-i: Go into interactive mode also; listen for TCP connections;\n\
  20423. X    each connection is limited to 'duration' seconds.\n");
  20424. X#else
  20425. Xfprintf (stderr, "Usage: serverd [-1] [-e] [-l load]\n\
  20426. X-1: Execute only once.\n\
  20427. X-e: Echo reports to the screen.\n\
  20428. X-l: Enforce load restrictions.\n");
  20429. X#endif
  20430. X  exit (3);
  20431. X}
  20432. X
  20433. X/*
  20434. X  Graceful exit. Remove pid file.
  20435. X*/
  20436. X
  20437. Xint gexit (int exitcode)
  20438. X{
  20439. X  unlink (PID_SERVERD);
  20440. X#ifndef NO_LOCKS
  20441. X  unlock_file (lfd);
  20442. X#endif
  20443. X#ifdef GO_INTERACTIVE
  20444. X  if (interactive) {
  20445. X    kill (chpid, SIGINT);
  20446. X    while (!chdied);
  20447. X    semremove (sid);
  20448. X  }
  20449. X#endif
  20450. X  exit (exitcode);
  20451. X}
  20452. X
  20453. X/*
  20454. X  Wait MAX_TRIES * 30 seconds for load to drop to max_load.
  20455. X*/
  20456. X
  20457. Xvoid load_wait (float max_load)
  20458. X{
  20459. X  int try;
  20460. X  float load = 0.0;
  20461. X  FILE *loadf;
  20462. X
  20463. X  for (try = 0 ;; try++) {
  20464. X    syscom ("%s | %s \
  20465. X'{ \
  20466. X   for (i = 1; i < 20; ++i) \
  20467. X     if ($i == \"load\") \
  20468. X       if ($(i+1) == \"average:\") print $(i+2);\
  20469. X       else print $(i+1); \
  20470. X}' > %s",
  20471. X        UPTIME, AWK, LOAD_FILE);
  20472. X    OPEN_FILE (loadf, LOAD_FILE, "r", "load_wait");
  20473. X    fscanf (loadf, "%f", &load);
  20474. X    fclose (loadf);
  20475. X    unlink (LOAD_FILE);
  20476. X
  20477. X    if (load <= max_load)
  20478. X      break;
  20479. X
  20480. X    sleep (30);
  20481. X  }
  20482. X}
  20483. X
  20484. X/*
  20485. X  Execute 'command' using the system call.
  20486. X
  20487. X  USER CONTRIBUTED MODIFIED CODE (for version 5.5): Warren Burstein.
  20488. X*/
  20489. X
  20490. X#define  MYWEXITSTATUS(stat)    ((int)(((stat)>>8)&0377))
  20491. X
  20492. Xvoid run_program (char *command, BOOLEAN is_listproc, int msg_sock)
  20493. X{
  20494. X  int status, mask;
  20495. X  char msg [MAX_LINE];
  20496. X  char reply [MAX_LINE];
  20497. X
  20498. X  report_progress (report, command, TRUE);
  20499. X
  20500. X#ifdef GO_INTERACTIVE
  20501. X  if (ppid == getpid())
  20502. X# if defined (bsd)
  20503. X#  ifdef SIGCLD
  20504. X    mask = sigblock (sigmask (SIGCLD)),
  20505. X#  else
  20506. X    mask = sigblock (sigmask (SIGCHLD)),
  20507. X#  endif
  20508. X    status = system (command),
  20509. X    sigsetmask (mask);
  20510. X# elif (defined (svr4) || defined (svr3)) && !defined (stellar)
  20511. X#  ifdef SIGCLD
  20512. X    sighold (SIGCLD),
  20513. X#  else
  20514. X    sighold (SIGCHLD),
  20515. X#  endif
  20516. X    status = system (command),
  20517. X#  ifdef SIGCLD
  20518. X    sigrelse (SIGCLD);
  20519. X#  else
  20520. X    sigrelse (SIGCHLD);
  20521. X#  endif
  20522. X# else
  20523. X#  ifdef SIGCLD
  20524. X    signal (SIGCLD, SIG_DFL),
  20525. X#  else
  20526. X    signal (SIGCHLD, SIG_DFL),
  20527. X#  endif
  20528. X    status = system (command),
  20529. X#  ifdef SIGCLD
  20530. X    signal (SIGCLD, (void (*)()) sighandle);
  20531. X#  else
  20532. X    signal (SIGCHLD, (void (*)()) sighandle);
  20533. X#  endif
  20534. X# endif
  20535. X  else
  20536. X#endif
  20537. X    status = system (command);
  20538. X  if (status > 127) {
  20539. X    sprintf (msg, "%s %s: %s: %s",
  20540. X         (ppid == getpid() ? "serverd" : "ILP client"),
  20541. X         (MYWEXITSTATUS (status) == 7) ? "restarts" : "died",
  20542. X             is_listproc ? "LISTPROC" : "LIST",
  20543. X             (MYWEXITSTATUS (status) >= 0 && MYWEXITSTATUS (status) <= 16 ?
  20544. X          exit_string[MYWEXITSTATUS (status)] : exit_string[17]));
  20545. X    report_progress (report, msg, TRUE);
  20546. X    if (sys.options & BSD_MAIL)
  20547. X      syscom ("echo '' | %s -s '%s' %s", UCB_MAIL, msg, sys.manager);
  20548. X
  20549. X    if (is_listproc) {
  20550. X      if (MYWEXITSTATUS (status) == 6) { /* Shutdown request */
  20551. X#ifdef SYSLOG
  20552. X    closelog ();
  20553. X#else
  20554. X    fclose (report);
  20555. X#endif
  20556. X#ifdef GO_INTERACTIVE
  20557. X    if (interactive) {
  20558. X      CLOSE_CLIENT (msg_sock);
  20559. X      if (ppid == getpid()) /* Master process notifies */
  20560. X        gexit (6);    /* It will kill chpid */
  20561. X      exit (6);
  20562. X    }
  20563. X#endif
  20564. X    gexit (6);
  20565. X      }
  20566. X
  20567. X      if (MYWEXITSTATUS (status) == 7) { /* Restart request */
  20568. X    unlink (PID_SERVERD);
  20569. X#ifndef NO_LOCKS
  20570. X        unlock_file (lfd);
  20571. X#endif
  20572. X#ifdef GO_INTERACTIVE
  20573. X    if (interactive) {
  20574. X      CLOSE_CLIENT (msg_sock);
  20575. X      if (ppid == getpid()) { /* Master process notifies and continues */
  20576. X# ifdef SIGCLD
  20577. X        signal (SIGCLD, SIG_DFL);
  20578. X# else
  20579. X        signal (SIGCHLD, SIG_DFL);
  20580. X# endif
  20581. X        kill (chpid, SIGINT);
  20582. X        while (!chdied);
  20583. X        semremove (sid);
  20584. X      }
  20585. X      else
  20586. X        exit (7);
  20587. X    }
  20588. X#endif
  20589. X    signal (SIGALRM, SIG_IGN); /* Just in case */
  20590. X        execl (START, START, START_OPTIONS, NULL);
  20591. X        sprintf (msg, "serverd commits suicide: Could not restart \
  20592. Xsystem");
  20593. X        report_progress (report, msg, TRUE);
  20594. X#ifdef SYSLOG
  20595. X        closelog ();
  20596. X#else
  20597. X    fclose (report);
  20598. X#endif
  20599. X        if (sys.options & BSD_MAIL)
  20600. X          syscom ("echo '' | %s -s '%s' %s", UCB_MAIL, msg, sys.manager);
  20601. X#ifdef GO_INTERACTIVE
  20602. X    if (interactive)
  20603. X      exit (5);
  20604. X#endif
  20605. X    gexit (5);
  20606. X      }
  20607. X    }
  20608. X#ifdef SYSLOG
  20609. X    closelog ();
  20610. X#else
  20611. X    fclose (report);
  20612. X#endif
  20613. X#ifdef GO_INTERACTIVE
  20614. X    if (interactive) {
  20615. X      CLOSE_CLIENT (msg_sock);
  20616. X      if (ppid == getpid()) /* Master process notifies */
  20617. X    gexit (MYWEXITSTATUS (status));    /* Will kill chpid */
  20618. X      exit (MYWEXITSTATUS (status));
  20619. X    }
  20620. X#endif
  20621. X    gexit (MYWEXITSTATUS (status));
  20622. X  }
  20623. X
  20624. X  if (status == 127) {
  20625. X    sprintf (msg, "serverd died: could not execute shell for %s",
  20626. X             is_listproc ? "listproc" : "list");
  20627. X    if (sys.options & BSD_MAIL)
  20628. X      syscom ("echo '' | %s -s '%s' %s", UCB_MAIL, msg, sys.manager);
  20629. X    report_progress (report, msg, TRUE);
  20630. X#ifdef SYSLOG
  20631. X    closelog ();
  20632. X#else
  20633. X    fclose (report);
  20634. X#endif
  20635. X#ifdef GO_INTERACTIVE
  20636. X    if (interactive)
  20637. X      exit (5);
  20638. X#endif
  20639. X    gexit (5);
  20640. X  }
  20641. X  else if (status > 0 && status < 127) {
  20642. X    sprintf (msg, "serverd commits suicide: status %d while trying to \
  20643. Xspawn %s: no tty; see the documentation", status, command);
  20644. X    report_progress (report, msg, TRUE);
  20645. X#ifdef SYSLOG
  20646. X    closelog ();
  20647. X#else
  20648. X    fclose (report);
  20649. X#endif
  20650. X#ifdef GO_INTERACTIVE
  20651. X    if (interactive)
  20652. X      exit (5);
  20653. X#endif
  20654. X    gexit (5);
  20655. X  }
  20656. X  else if (status < 0)
  20657. X    report_progress (report, "Cannot get child exit status", TRUE);
  20658. X}
  20659. X
  20660. X#ifdef GO_INTERACTIVE
  20661. X/*
  20662. X  Handle signals, especially SIGCLD.
  20663. X*/
  20664. X
  20665. Xvoid sighandle (int sig)
  20666. X{
  20667. X#ifdef WAIT3_NEEDS_UNION
  20668. X  union wait status;
  20669. X#else
  20670. X  int status = 1;
  20671. X#endif
  20672. X  int pid, i, j, _nforks, mask, pids[MAX_CONNECTIONS], exstatus;
  20673. X  char reply [MAX_LINE];
  20674. X  BOOLEAN restart = FALSE;
  20675. X
  20676. X# ifdef SIGCLD
  20677. X  if (sig != SIGCLD)
  20678. X    signal (sig, SIG_IGN);
  20679. X  if (sig == SIGCLD) {
  20680. X# else
  20681. X  if (sig != SIGCHLD)
  20682. X    signal (sig, SIG_IGN);
  20683. X  if (sig == SIGCHLD) {
  20684. X# endif
  20685. X# if defined (bsd)
  20686. X#  ifdef SIGCLD
  20687. X    mask = sigblock (sigmask (SIGCLD));
  20688. X#  else
  20689. X    mask = sigblock (sigmask (SIGCHLD));
  20690. X#  endif
  20691. X# elif defined (svr4) || defined (svr3)
  20692. X#  ifdef SIGCLD
  20693. X    sighold (SIGCLD);
  20694. X#  else
  20695. X    sighold (SIGCHLD);
  20696. X#  endif
  20697. X# endif
  20698. X    if (ppid == getpid()) {    /* Listener process died, or system() bug */
  20699. X# if defined (sequent) || defined (stardent) || defined (stellar) || \
  20700. X  defined (titan) || defined (unknown_port)
  20701. X      do {
  20702. X    pid = wait3 (&status, WNOHANG, NULL);
  20703. X      } while (pid && pid != chpid);
  20704. X# else
  20705. X      pid = waitpid (chpid, &status, WNOHANG);
  20706. X# endif
  20707. X      if (!pid) {    /* system() bug */
  20708. X# if defined (bsd)
  20709. X    sigsetmask (mask);
  20710. X# elif defined (svr3) || defined (svr4)
  20711. X#  ifdef SIGCLD
  20712. X    sigrelse (SIGCLD);
  20713. X#  else
  20714. X    sigrelse (SIGCHLD);
  20715. X#  endif
  20716. X# endif
  20717. X    signal (sig, (void (*)()) sighandle);
  20718. X    return;
  20719. X      }
  20720. X    }
  20721. X    else    /* Listener process: "live" child died */
  20722. X      pid = wait (&status);   /* Get child's pid */
  20723. X    for (i = 0; i < nforks; i++) {
  20724. X      if (clients [i].pid == pid) { /* Remove dead child's pid */
  20725. X    report_progress (report,
  20726. X             tsprintf ("Connection closed with %s (client #%d)",
  20727. X                   clients [i].name, clients [i].connid), TRUE);
  20728. X    for (j = i; j < nforks - 1; j++)
  20729. X    memcpy ((char *) &clients [j], (char *) &clients [j + 1], 
  20730. X        sizeof (CLIENT));
  20731. X    break;
  20732. X      }
  20733. X    }
  20734. X    if (i == nforks && chpid == getpid())
  20735. X      report_progress (report, "Connection closed with last client", TRUE);
  20736. X    --nforks;
  20737. X    if (WIFSIGNALED (status))  {
  20738. X      if (WTERMSIG (status) > SIGINT &&
  20739. X      WTERMSIG (status) != ABORT_SIG && WTERMSIG (status) != TIMEOUT_SIG)
  20740. X    report_progress (report, tsprintf ("\nsighandle(): Child died \
  20741. Xabnormally: signal %d",
  20742. X                       WTERMSIG (status)), TRUE);
  20743. X    }
  20744. X    else if (WIFEXITED (status)) { /* Abnormal child exit status ? */
  20745. X      if ((exstatus = WEXITSTATUS (status)) == 0 && pid != chpid) {
  20746. X# if defined (bsd)
  20747. X    sigsetmask (mask);
  20748. X# elif defined (svr3) || defined (svr4)
  20749. X#  ifdef SIGCLD
  20750. X    sigrelse (SIGCLD);
  20751. X#  else
  20752. X    sigrelse (SIGCHLD);
  20753. X#  endif
  20754. X# endif
  20755. X    signal (sig, (void (*)()) sighandle);
  20756. X    return;
  20757. X      }
  20758. X      if (exstatus == 6 || exstatus == 7 || exstatus == 8 || exstatus == 11 ||
  20759. X      exstatus == 13 || exstatus == 14 || exstatus == 15 || exstatus == 16) {
  20760. X       /* Shutdown or restart request, semaphore/socket error */
  20761. X    if (exstatus == 7 && ppid == getpid())
  20762. X      restart = TRUE; /* Only master process may restart */
  20763. X    else if (exstatus == 8)
  20764. X      report_progress (report, "\nsighandle(): Child received SIGTERM",
  20765. X               TRUE);
  20766. X    else if (exstatus == 13 || exstatus == 15) {
  20767. X      report_progress (report,
  20768. X               tsprintf ("\nsighandle(): Child experienced %s \
  20769. Xerror", (exstatus == 13 ? "socket" : "setuid()/setgid()")), TRUE);
  20770. X# if defined (bsd)
  20771. X      sigsetmask (mask);
  20772. X# elif defined (svr3) || defined (svr4)
  20773. X#  ifdef SIGCLD
  20774. X      sigrelse (SIGCLD);
  20775. X#  else
  20776. X      sigrelse (SIGCHLD);
  20777. X#  endif
  20778. X# endif
  20779. X      signal (sig, (void (*)()) sighandle);
  20780. X      return;
  20781. X    }
  20782. X    else if (exstatus == 11 || exstatus == 14 || exstatus == 16)
  20783. X      report_progress (report,
  20784. X               tsprintf ("\nsighandle(): Child experienced %s\
  20785. X error", ((exstatus == 11 ? "malloc()" : 
  20786. X       (exstatus == 14 ? "semaphore" : "internal")))), TRUE);
  20787. X    if (ppid != getpid()) { /* Master process will exit gracefully */
  20788. X      _nforks = nforks; /* As children die nforks decreases */
  20789. X# if defined (bsd)
  20790. X      sigsetmask (mask);
  20791. X# elif defined (svr3) || defined (svr4)
  20792. X#  ifdef SIGCLD
  20793. X      sigrelse (SIGCLD);
  20794. X#  else
  20795. X      sigrelse (SIGCHLD);
  20796. X#  endif
  20797. X# endif
  20798. X      signal (sig, (void (*)()) sighandle);
  20799. X      for (i = 0; i < _nforks; i++)
  20800. X        pids[i] = clients [i].pid;
  20801. X      for (i = 0; i < _nforks; i++) /* Kill any "live" children */
  20802. X        kill (pids[i], ABORT_SIG);
  20803. X      kill (ppid, ABORT_SIG);
  20804. X      exit (exstatus);
  20805. X    }
  20806. X      }
  20807. X    }
  20808. X# if defined (bsd)
  20809. X    sigsetmask (mask);
  20810. X# elif defined (svr3) || defined (svr4)
  20811. X#  ifdef SIGCLD
  20812. X    sigrelse (SIGCLD);
  20813. X#  else
  20814. X    sigrelse (SIGCHLD);
  20815. X#  endif
  20816. X# endif
  20817. X    signal (sig, (void (*)()) sighandle);
  20818. X    if (ppid != getpid()) /* Master process will die */
  20819. X      return;
  20820. X    else if (pid != chpid) /* Master cares only about the Listener process */
  20821. X      return;
  20822. X    unlink (PID_SERVERD);
  20823. X  }
  20824. X# ifdef SIGCLD
  20825. X  signal (SIGCLD, SIG_DFL);
  20826. X# else
  20827. X  signal (SIGCHLD, SIG_DFL);
  20828. X# endif
  20829. X  if (chpid == getpid()) { /* Listener process */
  20830. X    for (i = 0; i < nforks; i++) { /* Kill any "live" children */
  20831. X      report_progress (report, tsprintf ("Connection closed with %s (client #%d)",
  20832. X                     clients [i].name, clients [i].connid),
  20833. X               TRUE);
  20834. X      kill (clients [i].pid, ABORT_SIG);
  20835. X    }
  20836. X    while (still_delivering_mail (sid) > 0); /* Wait for list to terminate */
  20837. X    kill (ppid, ABORT_SIG);  /* Notify master process we are dying */
  20838. X  }
  20839. X  /* Next two lines are currently useless; kept for future use */
  20840. X  if (getpid() != chpid && getpid() != ppid) /* Live process */
  20841. X    CLOSE_CLIENT (msg_sock);
  20842. X  if (ppid == getpid ())
  20843. X    semremove (sid);    /* Only master process may remove it */
  20844. X  if (restart) {
  20845. X# ifndef NO_LOCKS
  20846. X    unlock_file (lfd);
  20847. X# endif
  20848. X    execl (START, START, START_OPTIONS, NULL);
  20849. X    report_progress (report, "serverd commits suicide: Could not restart system",
  20850. X             TRUE);
  20851. X# ifdef SYSLOG
  20852. X    closelog ();
  20853. X# else
  20854. X    fclose (report);
  20855. X# endif
  20856. X    if (sys.options & BSD_MAIL)
  20857. X      syscom ("echo '' | %s -s '%s' %s", UCB_MAIL, reply, sys.manager);
  20858. X    exit (5);
  20859. X  }
  20860. X# ifndef NO_LOCKS
  20861. X  unlock_file (lfd);
  20862. X# endif
  20863. X# ifdef SYSLOG
  20864. X  closelog ();
  20865. X# else
  20866. X  fclose (report);
  20867. X# endif
  20868. X  exit (0);
  20869. X}
  20870. X
  20871. X/*
  20872. X  Called when Listener process has exited.
  20873. X*/
  20874. X
  20875. Xvoid listener_exited ()
  20876. X{
  20877. X  chdied = TRUE;
  20878. X}
  20879. X
  20880. X/*
  20881. X  Child has been notified that it should commit suicide, so it does after
  20882. X  notifying the client.
  20883. X*/
  20884. X
  20885. Xvoid close_connection (int sig)
  20886. X{
  20887. X  char s [256];
  20888. X
  20889. X  signal (sig, SIG_IGN);
  20890. X  if (sig == TIMEOUT_SIG || sig == SIGALRM)
  20891. X    sprintf (s, "%d %d \n%s", CONN_TIMEOUT, strlen (CONN_TIMED_OUT),
  20892. X         CONN_TIMED_OUT);
  20893. X  else if (sig == SIGTERM)
  20894. X    sprintf (s, "%d %d \n%s", CONN_CLOSED, strlen (GOOD_BYE), GOOD_BYE);
  20895. X  else if (sig == ABORT_SIG)
  20896. X    sprintf (s, "%d %d \n%s", CONN_ABORTED, strlen (SERVER_SHUTS_DOWN),
  20897. X         SERVER_SHUTS_DOWN);
  20898. X  else
  20899. X    sprintf (s, "%d %d \n%s", CONN_ABORTED, strlen (REMOTE_SYS_ERROR),
  20900. X         REMOTE_SYS_ERROR);
  20901. X  write_to_fd (msg_sock, s, strlen (s));
  20902. X  close (msg_sock);
  20903. X# ifndef SYSLOG
  20904. X  fclose (report);
  20905. X# endif
  20906. X  unlink (requests_file);
  20907. X  unlink (mailforwardf);
  20908. X  _exit (0);
  20909. X}
  20910. X
  20911. X/*
  20912. X  Check whether a child process has been running longer than 'conn_duration'
  20913. X  seconds and return its pid, or 0 otherwise.
  20914. X*/
  20915. X
  20916. Xint check_timeout (CLIENT clients [])
  20917. X{
  20918. X  int i;
  20919. X
  20920. X  for (i = 0; i < nforks; i++)
  20921. X    if ((time (0) - clients [i].time) > conn_duration)
  20922. X      return clients [i].pid;
  20923. X  return 0;
  20924. X}
  20925. X
  20926. X/*
  20927. X  Create a socket and bind it to the local address and to an available port.
  20928. X  Return the socket file descriptor, or -1 on error.
  20929. X*/
  20930. X
  20931. Xint create_connection ()
  20932. X{
  20933. X  struct sockaddr_in server;
  20934. X  struct servent *service;
  20935. X  struct hostent *hostentry;
  20936. X  int sock, timeout = 0, sendbuf = BUFFSIZ, recvbuf = BUFFSIZ, val = 1;
  20937. X
  20938. X# ifndef ILP_PORT
  20939. X  if (! (service = getservbyname (SERVICE, NULL))) {
  20940. X    report_progress (report, "\ncreate_connection(): Service unavailable",
  20941. X             TRUE);
  20942. X    return -1;
  20943. X  }
  20944. X# endif
  20945. X  if (! (hostentry = gethostbyname ("localhost"))) {
  20946. X    report_progress (report, "\ncreate_connection(): No such host", TRUE);
  20947. X    return -1;
  20948. X  }
  20949. X  if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  20950. X    report_progress (report, "\ncreate_connection(): Could not create socket",
  20951. X             TRUE);
  20952. X    return -1;
  20953. X  }
  20954. X  if (setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *) &sendbuf,
  20955. X          sizeof (sendbuf)) < 0)
  20956. X    report_progress (report, "\ncreate_connection(): WARNING: Could not \
  20957. Xset send-buffer size: setsockopt() error", TRUE);
  20958. X  if (setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *) &recvbuf,
  20959. X          sizeof (recvbuf)) < 0)
  20960. X    report_progress (report, "\ncreate_connection(): WARNING: Could not \
  20961. Xset receive-buffer size: setsockopt() error", TRUE);
  20962. X  if (setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
  20963. X      sizeof (val)) < 0)
  20964. X    report_progress (report, "\ncreate_connection():WARNING: Cannot toggle \
  20965. Xkeep-alive connections: setsockopt() error", TRUE);
  20966. X  val = 1;
  20967. X  if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
  20968. X      sizeof (val)) < 0)
  20969. X    report_progress (report, "\ncreate_connection():WARNING: Cannot toggle \
  20970. Xreuse of local address: setsockopt() error", TRUE);
  20971. X
  20972. X  server.sin_family = AF_INET;            /* Internet protocol */
  20973. X  server.sin_addr.s_addr = INADDR_ANY;
  20974. X# ifndef ILP_PORT
  20975. X  server.sin_port = service->s_port;
  20976. X# else
  20977. X  server.sin_port = htons (ILP_PORT);
  20978. X# endif
  20979. X
  20980. X  while (bind (sock, (struct sockaddr *) &server, sizeof (server)) < 0 &&
  20981. X     errno == EADDRINUSE && timeout < 180) { /* For perm port keep trying */
  20982. X    ++timeout;
  20983. X    errno = 0;
  20984. X    sleep (1);
  20985. X  }
  20986. X  if (timeout >= 180) {
  20987. X    report_progress (report, "\ncreate_connection(): Could not bind", TRUE);
  20988. X    return -1;
  20989. X  }
  20990. X  listen (sock, 5);
  20991. X  return sock;
  20992. X}
  20993. X
  20994. X/*
  20995. X  Process all live requests coming in from the tcp connection.
  20996. X
  20997. X  PLEASE DO NOT MODIFY THIS ROUTINE AS YOU MAY BREAK THE PROTOCOL AND CREATE
  20998. X  HAVOC WITH PEER INTERACTIVE LISTPROCESSORS. A LOT OF UNDOCUMENTED
  20999. X  ASSUMPTIONS ARE MADE. YOU SHOULD CONTACT ME ABOUT ANY CHANGES YOU WISH TO
  21000. X  MAKE.
  21001. X
  21002. X  [What a messy routine]
  21003. X*/
  21004. X
  21005. Xvoid process_live_request (int msg_sock, struct sockaddr_in client)
  21006. X{
  21007. X  char ch, *buf, *dash, server [MAX_LINE], msg [MAX_LINE], replyf[MAX_LINE];
  21008. X  char denied_req [6][MAX_LINE], login [MAX_LINE], *passwd;
  21009. X  char *perms [6], *s, *r, *rr;
  21010. X  char outfile [MAX_LINE], reply [MAX_LINE], arg [MAX_LINE];
  21011. X  char localhost [MAX_LINE], _localhost [MAX_LINE], localaddr [MAX_LINE];
  21012. X  char rhost [MAX_LINE], raddr [MAX_LINE];
  21013. X  FILE *f;
  21014. X#ifdef ultrix
  21015. X  time_t t, time_started;
  21016. X#else
  21017. X  long int t, time_started;
  21018. X#endif
  21019. X  long int sig_mask, naddr, naddr2, nlines, buffsiz = BUFFSIZ;
  21020. X  long int i, j, value, nfds, total_bytes_written = 0, mask;
  21021. X  int response, fmode, l, auth = NOTSUBSCRIBED, bytes_read = 0, rcode;
  21022. X  int listid, lckmask;
  21023. X  BOOLEAN more_input = FALSE, reply_code, bin = TRUE, put_request,
  21024. X    already_aborted = TRUE;
  21025. X  struct hostent *hp, *rhp;
  21026. X  struct stat stat_buf;
  21027. X  struct in_addr _addr;
  21028. X
  21029. X  sprintf (denied_req [MANAGER], "-d execute -d fax");
  21030. X  sprintf (denied_req [OWNER], "%s -d shutdown -d restart",
  21031. X       denied_req [MANAGER]);
  21032. X  sprintf (denied_req [SUBSCRIBED], "%s -d subscribe -d system -d reports \
  21033. X-d edit -d put -d approve -d discard", denied_req [OWNER]);
  21034. X  sprintf (denied_req [NOTSUBSCRIBED], "%s -d unsubscribe -d set -d which \
  21035. X-d run",
  21036. X       denied_req [SUBSCRIBED]);
  21037. X  perms [MANAGER] = MANAGER_LOGIN;
  21038. X  perms [OWNER] = OWNER_LOGIN;
  21039. X  perms [SUBSCRIBED] = SUBSCRIBER_LOGIN;
  21040. X  perms [NOTSUBSCRIBED] = GENERAL_LOGIN;
  21041. X
  21042. X  sprintf (mailforwardf, "%s.%d", TMP_LIVE, getpid());
  21043. X  sprintf (replyf, "%s.%d", ULISTPROCESSOR_REPLY, getpid());
  21044. X  time_started = time (0);
  21045. X  if (gethostname (localhost, sizeof (localhost))) {
  21046. X    report_progress (report, tsprintf ("\nprocess_live_request(): gethostname()\
  21047. X failed: errno %d", errno), TRUE);
  21048. X    CLIENT_LOST (13);
  21049. X  }
  21050. X  strcpy (_localhost, localhost);
  21051. X  upcase (_localhost);
  21052. X  if (write_to_fd (msg_sock, LOGIN, strlen (LOGIN)) < 0)
  21053. X    CLIENT_LOST (13);
  21054. X  outfile[0] = RESET (login);
  21055. X  GET_LOGIN (login);
  21056. X  if (!strncmp (login, "__abort__", 9)) /* Client aborted -- Reserved */
  21057. X    goto ciao;
  21058. X  if (login [0] != EOS) { /* Proceed with authentication */
  21059. X    strcpy (msg, login);  /* Used to form a "From " line */
  21060. X    rr = s = mystrdup (login);
  21061. X    upcase (s);
  21062. X    while ((s = _strstr (s, "IUL:"))) {
  21063. X      s += 4;    /* Point to remote host */
  21064. X      sscanf (s, "%s", rhost);
  21065. X      if ((r = strchr (rhost, ';')))
  21066. X    *r = EOS;
  21067. X      if (!strcmp (rhost, _localhost)) { /* Loop */
  21068. X    sprintf (msg, "Loop detected.\n");
  21069. X    REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
  21070. X    write_to_fd (msg_sock, msg, strlen (msg));
  21071. X    goto ciao;
  21072. X      }
  21073. X      rhp = hp = gethostbyname (rhost);
  21074. X      if (hp) {
  21075. X    if ((rhp = (struct hostent *) malloc (sizeof (struct hostent))) == NULL)
  21076. X      report_progress (report, "\nprocess_live_request(): malloc() failed",
  21077. X               TRUE),
  21078. X      exit (11);
  21079. X    memcpy ((char *) rhp, (char *) hp, sizeof (*hp));
  21080. X# ifdef h_addr
  21081. X    if ((rhp->h_addr_list = (char **) malloc (sizeof (char *))) == NULL)
  21082. X      report_progress (report, "\nprocess_live_request(): malloc() failed",
  21083. X               TRUE),
  21084. X      exit (11);
  21085. X    naddr = 0;
  21086. X    while (hp->h_addr_list[naddr]) {
  21087. X      if ((rhp->h_addr_list = (char **)
  21088. X           realloc (rhp->h_addr_list, (naddr + 2) * sizeof (char *))) ==
  21089. X          NULL)
  21090. X        report_progress (report,
  21091. X                 "\nprocess_live_request(): realloc() failed", TRUE),
  21092. X        exit (11);
  21093. X      if ((rhp->h_addr_list[naddr] = (char *)
  21094. X           malloc (rhp->h_length * sizeof (char))) == NULL)
  21095. X        report_progress (report,
  21096. X                 "\nprocess_live_request(): malloc() failed", TRUE),
  21097. X        exit (11);
  21098. X      memcpy ((char *) rhp->h_addr_list[naddr],
  21099. X          (char *) hp->h_addr_list[naddr], hp->h_length);
  21100. X      rhp->h_addr_list[++naddr] = NULL;
  21101. X    }
  21102. X    naddr = 0;
  21103. X    while (rhp->h_addr_list[naddr]) {
  21104. X      memcpy ((char *) &_addr, (char *) rhp->h_addr_list[naddr++],
  21105. X          rhp->h_length);
  21106. X      strcpy (raddr, (char *) inet_ntoa (_addr));
  21107. X      hp = gethostbyname (localhost);
  21108. X      naddr2 = 0;
  21109. X      while (hp && hp->h_addr_list[naddr2]) {
  21110. X        memcpy ((char *) &_addr, (char *) hp->h_addr_list[naddr2++],
  21111. X            hp->h_length);
  21112. X        strcpy (localaddr, (char *) inet_ntoa (_addr));
  21113. X        if (!strcmp (raddr, localaddr)) { /* Loop */
  21114. X          sprintf (msg, "Loop detected.\n");
  21115. X          REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
  21116. X          write_to_fd (msg_sock, msg, strlen (msg));
  21117. X          goto ciao;
  21118. X        }
  21119. X      }
  21120. X    }
  21121. X    naddr = 0;
  21122. X    while (rhp->h_addr_list[naddr])
  21123. X      free ((char *) rhp->h_addr_list[naddr++]);
  21124. X    free ((char **) rhp->h_addr_list);
  21125. X# else
  21126. X    if ((rhp->h_addr = (char *) malloc ((strlen (hp->h_addr) + 1) *
  21127. X                        sizeof (char))) == NULL)
  21128. X      report_progress (report, "\nprocess_live_request(): malloc() failed",
  21129. X               TRUE),
  21130. X      exit (11);
  21131. X    memcpy ((char *) rhp->h_addr, (char *) hp->h_addr, hp->h_length);
  21132. X    memcpy ((char *) &_addr, (char *) rhp->h_addr, rhp->h_length);
  21133. X    strcpy (raddr, (char *) inet_ntoa (_addr));
  21134. X    hp = gethostbyname (rhost);
  21135. X    memcpy ((char *) &_addr, (char *) hp->h_addr, hp->h_length);
  21136. X    strcpy (localaddr, (char *) inet_ntoa (_addr));
  21137. X    if (!strcmp (raddr, localaddr)) { /* Loop */
  21138. X      sprintf (msg, "Loop detected.\n");
  21139. X      REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
  21140. X      write_to_fd (msg_sock, msg, strlen (msg));
  21141. X      goto ciao;
  21142. X    }
  21143. X    free ((char *) rhp->h_addr);
  21144. X# endif
  21145. X    free ((struct hostent *) rhp);
  21146. X      }
  21147. X      hp = gethostbyname (localhost);
  21148. X      naddr = 0;
  21149. X# ifdef h_addr
  21150. X      while (hp && hp->h_addr_list[naddr]) {
  21151. X    memcpy ((char *) &_addr, (char *) hp->h_addr_list[naddr++],
  21152. X        hp->h_length);
  21153. X    strcpy (localaddr, (char *) inet_ntoa (_addr));
  21154. X    if (!strcmp (rhost, localaddr)) { /* Loop */
  21155. X      sprintf (msg, "Loop detected.\n");
  21156. X      REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
  21157. X      write_to_fd (msg_sock, msg, strlen (msg));
  21158. X      goto ciao;
  21159. X    }
  21160. X      }
  21161. X# else
  21162. X      memcpy ((char *) &_addr, (char *) hp->h_addr, hp->h_length);
  21163. X      strcpy (localaddr, (char *) inet_ntoa (_addr));
  21164. X      if (!strcmp (rhost, localaddr)) { /* Loop */
  21165. X    sprintf (msg, "Loop detected.\n");
  21166. X    REPLY (msg_sock, PEER_UNAVAIL, strlen (msg));
  21167. X    write_to_fd (msg_sock, msg, strlen (msg));
  21168. X    goto ciao;
  21169. X      }
  21170. X# endif
  21171. X    }
  21172. X    free ((char *) rr);
  21173. X    REPLY (msg_sock, PASSWORD_REQUIRED, strlen (PASSWORD));
  21174. X    if (write_to_fd (msg_sock, PASSWORD, strlen (PASSWORD)) < 0)
  21175. X      CLIENT_LOST (13);
  21176. X    if ((passwd = (char *) malloc (MAX_LINE * sizeof (char))) == NULL)
  21177. X      report_progress (report,
  21178. X               "\nprocess_live_request(): malloc() failed", TRUE),
  21179. X      exit (11);
  21180. X    RESET (passwd);
  21181. X    GET_LOGIN (passwd);
  21182. X    if (!strncmp (passwd, "__abort__", 9)) /* Client aborted -- Reserved */
  21183. X      goto ciao;
  21184. X    upcase (passwd);
  21185. X    if (!strcmp (login, sys.manager)) /* Check to see if he's the manager */
  21186. X      if (!strcmp (passwd, sys.server.password)) {
  21187. X    auth = MANAGER;
  21188. X    REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
  21189. X    if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
  21190. X      CLIENT_LOST (13);
  21191. X    goto skip;
  21192. X      }
  21193. X    upcase (login);
  21194. X    for (listid = 0; listid < nlists; listid++) /* Check to see if he is an owner */
  21195. X      if (owner_listed (OWNERSF, login, sys.lists[listid].alias, report) ==
  21196. X      OWNER)
  21197. X    if (!strcmp (passwd, sys.lists[listid].password)) {
  21198. X      auth = OWNER;
  21199. X      REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
  21200. X      if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
  21201. X        CLIENT_LOST (13);
  21202. X      goto skip;
  21203. X    }
  21204. X
  21205. X    for (listid = 0; listid < nlists; listid++) { /* Check for regular subscription */
  21206. X      setup_string (subscribersf, sys.lists[listid].alias, SUBSCRIBERS);
  21207. X      sprintf (password_in_sub_file, "%ld", time (0));
  21208. X      if (subscribed (report, login, subscribersf, NULL, NULL, NULL, TRUE) ==
  21209. X      SUBSCRIBED)
  21210. X    if (!strcmp (passwd, password_in_sub_file)) {
  21211. X      auth = SUBSCRIBED;
  21212. X      REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
  21213. X      if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
  21214. X        CLIENT_LOST (13);
  21215. X      goto skip;
  21216. X        }
  21217. X    }
  21218. X  }
  21219. X  else
  21220. X    REPLY (msg_sock, OK, 0);
  21221. X  REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
  21222. X  if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
  21223. X    CLIENT_LOST (13);
  21224. X  hp = gethostbyaddr ((char *) &client.sin_addr,
  21225. X              sizeof (struct in_addr), client.sin_family);
  21226. X  sprintf (msg, "IUL:%s;%s",
  21227. X       (hp ? hp->h_name : (char *) inet_ntoa (client.sin_addr)),
  21228. X       login);
  21229. X
  21230. X skip:
  21231. X  hp = gethostbyaddr ((char *) &client.sin_addr,
  21232. X              sizeof (struct in_addr), client.sin_family);
  21233. X  if (write_to_fd (msg_sock, PROMPT, strlen (PROMPT)) < 0)
  21234. X    CLIENT_LOST (13);
  21235. X
  21236. X  if ((buf = (char *) malloc (buffsiz * sizeof (char))) == NULL)
  21237. X    report_progress (report,
  21238. X             "\nprocess_live_request(): malloc() failed", TRUE),
  21239. X    exit (11);
  21240. X
  21241. X  ch = RESET (buf);
  21242. X
  21243. X  while (ch != EOF && bytes_read < MAX_LINE) { /* Get request & process it */
  21244. X    errno = 0;
  21245. X    if (read (msg_sock, &ch, 1) <= 0) {
  21246. X      if (errno == EINTR
  21247. X# ifdef ERESTART
  21248. X      || errno == ERESTART
  21249. X# endif
  21250. X      )
  21251. X    continue;
  21252. X      break;
  21253. X    }
  21254. X    if (time (0) - time_started > conn_duration) /* In case SIGALRM f_cks up */
  21255. X      close_connection (TIMEOUT_SIG);
  21256. X    ++bytes_read;
  21257. X    if (ch >= ' ' || (isspace (ch) && ch != '\r') || ch == '\03') {
  21258. X# ifndef NO_ABORT_OP
  21259. X      if (ch == '\03') {
  21260. X    if (!already_aborted) {
  21261. X      sprintf (urgmsg, "%08ld", total_bytes_written);
  21262. X      SEND_OOB_BYTE;
  21263. X      SEND_MSG;
  21264. X      REPLY (msg_sock, OK, strlen (PROMPT));
  21265. X      if (write_to_fd (msg_sock, PROMPT, strlen (PROMPT)) < 0)
  21266. X        CLIENT_LOST (13);
  21267. X    }
  21268. X        continue;
  21269. X      }
  21270. X# endif
  21271. X      if (ch != '\n') /* Buffer request */
  21272. X    buf [(l = strlen (buf))] = ch,
  21273. X    buf [l + 1] = EOS;
  21274. X      else {    /* End of request? process it */
  21275. X    if (strlen (buf) && buf [strlen (buf) - 1] == '&') { /* Request continues */
  21276. X      buf [strlen (buf) - 1] = EOS; /* Replace & */
  21277. X      REPLY (msg_sock, CONTINUED, strlen (CONT_PROMPT));
  21278. X      if (write_to_fd (msg_sock, CONT_PROMPT, strlen (CONT_PROMPT)) < 0)
  21279. X        CLIENT_LOST (13);
  21280. X      continue;
  21281. X    }
  21282. X    if (!more_input) {
  21283. X      clean_request (buf);
  21284. X      if (!strncmp (buf, "quit", 4) || !strncmp (buf, "exit", 4))
  21285. X        break;
  21286. X      if (!strncmp (buf, "__abort__", 9)) /* Reserved */
  21287. X        goto ciao;
  21288. X# ifdef bsd
  21289. X      sig_mask = sigblock (sigmask (SIGALRM) | sigmask (TIMEOUT_SIG));
  21290. X# elif defined (svr4) || defined (svr3)
  21291. X      sighold (SIGALRM);
  21292. X      sighold (TIMEOUT_SIG);
  21293. X# endif
  21294. X      if (!strncmp (buf, "binary", 3)) {
  21295. X        bin = TRUE;
  21296. X        REPLY (msg_sock, OK, strlen (BINARY_XFER) + strlen (PROMPT));
  21297. X        if (write_to_fd (msg_sock, BINARY_XFER, strlen (BINARY_XFER)) < 0)
  21298. X          CLIENT_LOST (13);
  21299. X        goto Skip;
  21300. X      }
  21301. X      if (!strncmp (buf, "ascii", 3)) {
  21302. X        bin = FALSE;
  21303. X        REPLY (msg_sock, OK, strlen (ASCII_XFER) + strlen (PROMPT));
  21304. X        if (write_to_fd (msg_sock, ASCII_XFER, strlen (ASCII_XFER)) < 0)
  21305. X          CLIENT_LOST (13);
  21306. X        goto Skip;
  21307. X      }
  21308. X      if (buf [0] == '?' || !strncmp (buf, "privileges", 4)) {
  21309. X        REPLY (msg_sock, OK, strlen (perms [auth]) + strlen (PROMPT));
  21310. X        if (write_to_fd (msg_sock, perms [auth], strlen (perms [auth])) < 0)
  21311. X          CLIENT_LOST (13);
  21312. X        goto Skip;
  21313. X      }
  21314. X      if (!strncmp (buf, "timeleft", 4)) {
  21315. X        sprintf (buf, "Time left: %d seconds\n", conn_duration - time (0) +
  21316. X             time_started);
  21317. X        REPLY (msg_sock, OK, strlen (buf) + strlen (PROMPT));
  21318. X        if (write_to_fd (msg_sock, buf, strlen (buf)) < 0)
  21319. X          CLIENT_LOST (13);
  21320. X        goto Skip;
  21321. X      }
  21322. X
  21323. X      sprintf (requests_file, "%s.r%d", TMP_LIVE, getpid());
  21324. X      OPEN_FILE (f, requests_file, "w", "process_live_request");
  21325. X      chown (requests_file, pwentry->pw_uid, pwentry->pw_gid);
  21326. X      t = time (0);
  21327. X      fprintf (f, "From %s %sComment: ILP connection from %s\nAccess: ",
  21328. X           msg, ctime (&t),
  21329. X           (hp ? hp->h_name : (char *) inet_ntoa (client.sin_addr)));
  21330. X      if (auth == SUBSCRIBED)
  21331. X        fprintf (f, "Subscriber to list %s", sys.lists[listid].alias);
  21332. X      else if (auth == OWNER)
  21333. X        fprintf (f, "Owner of list %s", sys.lists[listid].alias);
  21334. X      else if (auth == MANAGER)
  21335. X        fprintf (f, "Manager");
  21336. X      else
  21337. X        fprintf (f, "Casual");
  21338. X      fprintf (f, "\n\n");
  21339. X
  21340. X      put_request = FALSE;
  21341. X      RESET (arg);
  21342. X      sscanf (buf, "%s", arg);
  21343. X      if (re_strcmp ("^PUT$|^PUT[ \t]", upcase (arg), NULL) > 0) {
  21344. X        if (!check_for_redirection (buf, outfile, &fmode, msg_sock, bin)) {
  21345. X          fclose (f);
  21346. X          goto Skip;
  21347. X        }
  21348. X        if (outfile [0] != EOS &&
  21349. X        !writeable_file (outfile, msg_sock)) {
  21350. X          fclose (f);
  21351. X          goto Skip;
  21352. X        }
  21353. X        REPLY (msg_sock, MORE_INPUT_REQUIRED, strlen (MORE_INPUT));
  21354. X        if (write_to_fd (msg_sock, MORE_INPUT, strlen (MORE_INPUT)) < 0)
  21355. X          CLIENT_LOST (13);
  21356. X        more_input = TRUE;
  21357. X        reply_code = FALSE;
  21358. X        put_request = TRUE;
  21359. X        if (auth >= SUBSCRIBED && (dash = _strstr (buf, " - ")))
  21360. X          insert_word (dash + 1, &passwd, 1, 0, 1);
  21361. X      }
  21362. X    }
  21363. X
  21364. X    if (!strcmp (buf, ".") && more_input)
  21365. X      more_input = FALSE;
  21366. X    if (!strncmp (buf, "..", 2) && more_input)  /* Remove one dot */
  21367. X      for (l = 0; l < strlen (buf); l++)
  21368. X        buf [l] = buf [l + 1];
  21369. X
  21370. X    if (more_input && ch == '\n' && buf[0] == EOS)
  21371. X      strcat (buf, " ");    /* Kludge */
  21372. X
  21373. X    if (buf[0] != EOS) { /* Not \n only */
  21374. X
  21375. X      if (!more_input) {
  21376. X        if (!put_request) { /* Redirection has been checked and verified */
  21377. X          if (!check_for_redirection (buf, outfile, &fmode, msg_sock, bin)) {
  21378. X            fclose (f);
  21379. X            goto Skip;
  21380. X          }
  21381. X          RESET (arg);
  21382. X          sscanf (buf, "%s", arg);
  21383. X              if (outfile [0] != EOS || !strcmp (upcase (arg), "GET")) {
  21384. X            if (outfile [0] == EOS && !strcmp (arg, "GET"))
  21385. X          sscanf (buf, "%s %s %s", arg, arg, outfile),
  21386. X          fmode = (bin ? WRITE_TO_FILE_BIN : WRITE_TO_FILE_ASC);
  21387. X            if (!writeable_file (outfile, msg_sock)) {
  21388. X          fclose (f);
  21389. X              goto Skip;
  21390. X        }
  21391. X          }
  21392. X        }
  21393. X        if (strcmp (buf, ".")) {
  21394. X          if (auth >= SUBSCRIBED && (dash = _strstr (buf, " - ")))
  21395. X        insert_word (dash + 1, &passwd, 1, 0, 1);
  21396. X          fprintf (f, "%s\n", buf);
  21397. X        }
  21398. X        fclose (f);
  21399. X
  21400. X        sscanf (buf, "%s", arg);
  21401. X        upcase (arg);
  21402. X        lckmask = SEM_REQ_ID;
  21403. X        if (!strncmp (arg, "SET", 3) || !strncmp (arg, "UNS", 3) ||
  21404. X        !strncmp (arg, "REC", 3) || !strncmp (arg, "REV", 3) ||
  21405. X        !strncmp (arg, "INF", 3) || !strncmp (arg, "STA", 3) ||
  21406. X        !strncmp (arg, "WHI", 3) || !strncmp (arg, "REP", 3) ||
  21407. X        !strncmp (arg, "EDI", 3) || !strncmp (arg, "PUT", 3) ||
  21408. X        !strncmp (arg, "SYS", 3))
  21409. X          lckmask |= SEM_LISTFILES;
  21410. X        else if (!strncmp (arg, "IND", 3) || !strncmp (arg, "GET", 3) ||
  21411. X             !strncmp (arg, "SEA", 3) || !strncmp (arg, "VIE", 3))
  21412. X          lckmask |= SEM_ARCHIVES;
  21413. X        else if (!strncmp (arg, "SHU", 3) || !strncmp (arg, "RES", 3))
  21414. X          lckmask |= SEM_DLVR_MAIL;
  21415. X        CHECK_CRITICAL_SECTION ("process_live_request", msg_sock, lckmask);
  21416. X
  21417. X        sprintf (server, "%s -i %s %s -S %d -F %s -R %s -C %s", SERVER,
  21418. X             sys.server.cmdoptions, denied_req [auth], sid,
  21419. X             mailforwardf, requests_file, replyf);
  21420. X        run_program (server, TRUE, msg_sock);
  21421. X        unlink (requests_file);
  21422. X        if ((f = fopen (replyf, "r")) != NULL)
  21423. X          fscanf (f, "%d", &rcode),
  21424. X          fclose (f);
  21425. X        else
  21426. X          rcode = SYS_ERROR;
  21427. X# ifndef NO_ABORT_OP
  21428. X        already_aborted = FALSE;
  21429. X        SET_NONBLOCKING ("process_live_request");
  21430. X        errno = 0;
  21431. X        if ((value = recv (msg_sock, &ch, 1, MSG_OOB)) > 0)
  21432. X          if (ch == '\03')  {
  21433. X        strcat (urgmsg, "00000000");
  21434. X        SET_BLOCKING ("process_live_request");
  21435. X        SEND_OOB_BYTE;
  21436. X        SEND_MSG;
  21437. X        already_aborted = TRUE;
  21438. X        REPLY (msg_sock, OK, strlen (PROMPT));
  21439. X        goto Skip;
  21440. X          }
  21441. X          else
  21442. X        report_progress (report, 
  21443. X                 tsprintf ("\nprocess_live_request(): \
  21444. Xrecv(): unexpected char %c", ch), TRUE);
  21445. X        else if (value < 0 && errno && errno != EWOULDBLOCK &&
  21446. X             errno != EAGAIN && errno != EINTR && errno != EINVAL)
  21447. X          report_progress (report,
  21448. X                   tsprintf ("\nprocess_live_request(): \
  21449. Xrecv() failed: errno %d", errno), TRUE);
  21450. X
  21451. X        SET_BLOCKING ("process_live_request");
  21452. X# endif
  21453. X        if ((response = open (mailforwardf, O_RDONLY)) >= 0) {
  21454. X          stat (mailforwardf, &stat_buf);
  21455. X          nlines = 0;
  21456. X          if (outfile [0] != EOS &&
  21457. X          (rcode == WRITE_TO_FILE_ASC || rcode == WRITE_TO_FILE_BIN ||
  21458. X           rcode == OK || rcode == RESTRICTED_REQ ||
  21459. X           rcode == PERMISSION_DENIED)) {
  21460. X        if (!bin) { /* Count # of \n chars */
  21461. X          bytes_read = 1;
  21462. X          while (bytes_read > 0) {
  21463. X            errno = 0;
  21464. X            while ((bytes_read = read (response, buf, BUFFSIZ - 1)) < 0
  21465. X               && (errno == EINTR
  21466. X# ifdef ERESTART
  21467. X                   || errno == ERESTART)
  21468. X# else
  21469. X                  )
  21470. X# endif
  21471. X                   )
  21472. X              errno = 0;
  21473. X            if (errno && errno != EINTR
  21474. X# ifdef ERESTART
  21475. X            && errno != ERESTART
  21476. X# endif
  21477. X                ) {
  21478. X              unlink (mailforwardf);
  21479. X              CLOSE_CLIENT (msg_sock);
  21480. X# ifndef SYSLOG
  21481. X              fclose (report);
  21482. X# endif
  21483. X
  21484. X              _exit (13);
  21485. X            }
  21486. X            for (i = 0; i < bytes_read; ++i)
  21487. X              if (buf[i] == '\n') ++nlines;
  21488. X          }
  21489. X          lseek (response, 0L, SEEK_SET);
  21490. X        }
  21491. X        REPLY_FILE (msg_sock, fmode,
  21492. X                stat_buf.st_size + strlen (PROMPT) + nlines, 
  21493. X                outfile)
  21494. X          }
  21495. X          else
  21496. X            REPLY (msg_sock, rcode, stat_buf.st_size + strlen (PROMPT));
  21497. X          bytes_read = 1;
  21498. X          total_bytes_written = 0;
  21499. X          while (bytes_read > 0) {
  21500. X        errno = 0;
  21501. X        while ((bytes_read = read (response, buf, BUFFSIZ)) < 0
  21502. X               && (errno == EINTR
  21503. X# ifdef ERESTART
  21504. X               || errno == ERESTART)
  21505. X# else
  21506. X               )
  21507. X# endif
  21508. X              )
  21509. X          errno = 0;
  21510. X        if (errno && errno != EINTR
  21511. X# ifdef ERESTART
  21512. X            && errno != ERESTART
  21513. X# endif
  21514. X            ) {
  21515. X          unlink (mailforwardf);
  21516. X          CLOSE_CLIENT (msg_sock);
  21517. X# ifndef SYSLOG
  21518. X          fclose (report);
  21519. X# endif
  21520. X          _exit (13);
  21521. X        }
  21522. X        if (bytes_read > 0) {
  21523. X          if (!bin && outfile[0] != EOS &&
  21524. X              (rcode == WRITE_TO_FILE_ASC ||
  21525. X               rcode == WRITE_TO_FILE_BIN ||
  21526. X               rcode == OK || rcode == RESTRICTED_REQ ||
  21527. X               rcode == PERMISSION_DENIED))
  21528. X            for (i = 0; i < bytes_read; i++)
  21529. X              if (buf [i] == '\n') {
  21530. X            if (bytes_read == buffsiz)
  21531. X              if ((buf = (char *)
  21532. X                   realloc (buf, (++buffsiz) * sizeof (char))) ==
  21533. X                  NULL) {
  21534. X                unlink (mailforwardf);
  21535. X                report_progress (report, "\nprocess_live_request():\
  21536. X realloc() failed", TRUE),
  21537. X                exit (11);
  21538. X              }
  21539. X            for (j = bytes_read; j > i; j--)
  21540. X              buf [j] = buf [j - 1];
  21541. X            buf [i] = '\r';
  21542. X            ++bytes_read;
  21543. X            ++i;
  21544. X              }
  21545. X          if ((value = write_to_fd (msg_sock, buf, bytes_read)) < 0) {
  21546. X            unlink (mailforwardf);
  21547. X            CLIENT_LOST (13);
  21548. X          }
  21549. X          total_bytes_written += value;
  21550. X# ifndef NO_ABORT_OP
  21551. X          SET_NONBLOCKING ("process_live_request");
  21552. X          errno = 0;
  21553. X          if ((value = recv (msg_sock, &ch, 1, MSG_OOB)) > 0)
  21554. X            if (ch == '\03') {
  21555. X              sprintf (urgmsg, "%08ld", total_bytes_written);
  21556. X              SET_BLOCKING ("process_live_request");
  21557. X              SEND_OOB_BYTE;
  21558. X              SEND_MSG;
  21559. X              already_aborted = TRUE;
  21560. X              REPLY (msg_sock, OK, strlen (PROMPT));
  21561. X              break;
  21562. X            }
  21563. X            else
  21564. X              report_progress (report, 
  21565. X                       tsprintf ("\nprocess_live_request(): \
  21566. Xrecv(): unexpected char %c", ch), TRUE);
  21567. X          else if (value < 0 && errno && errno != EWOULDBLOCK &&
  21568. X               errno != EAGAIN && errno != EINTR && errno != EINVAL)
  21569. X            report_progress (report,
  21570. X                     tsprintf ("\nprocess_live_request(): \
  21571. Xrecv() failed: errno %d", errno), TRUE);
  21572. X          SET_BLOCKING ("process_live_request");
  21573. X# endif
  21574. X        }
  21575. X          }
  21576. X          close (response);
  21577. X        }
  21578. X        else
  21579. X          REPLY_ERROR (msg_sock, SYS_ERROR, strlen (REMOTE_SYS_ERROR) + 
  21580. X               strlen (PROMPT), REMOTE_SYS_ERROR);
  21581. X        RESET (outfile);
  21582. X      }
  21583. X      else {    /* More input */
  21584. X        fprintf (f, "%s\n", buf);
  21585. X        if (reply_code)    /* Kludge */
  21586. X          REPLY (msg_sock, OK, 0);
  21587. X        reply_code = TRUE;
  21588. X      }
  21589. X    }
  21590. X    else { /* Empty request */
  21591. X      fclose (f);
  21592. X      REPLY (msg_sock, OK, strlen (PROMPT));
  21593. X    }
  21594. X      Skip:
  21595. X    unlink (mailforwardf);
  21596. X    unlink (replyf);
  21597. X    if (!more_input)
  21598. X      if (write_to_fd (msg_sock, PROMPT, strlen (PROMPT)) < 0)
  21599. X        CLIENT_LOST (13);
  21600. X    bytes_read = 0;
  21601. X    ch = RESET (buf);
  21602. X# ifndef NO_ABORT_OP
  21603. X    SET_NONBLOCKING ("process_live_request");
  21604. X    errno = 0;
  21605. X    if ((value = recv (msg_sock, &ch, 1, MSG_OOB)) > 0)
  21606. X      if (ch == '\03') {
  21607. X        sprintf (urgmsg, "%08ld", total_bytes_written);
  21608. X        SET_BLOCKING ("process_live_request");
  21609. X        SEND_OOB_BYTE;
  21610. X        SEND_MSG;
  21611. X        already_aborted = TRUE;
  21612. X        REPLY (msg_sock, OK, strlen (PROMPT));
  21613. X        if (write_to_fd (msg_sock, PROMPT, strlen (PROMPT)) < 0)
  21614. X          CLIENT_LOST (13);
  21615. X      }
  21616. X      else
  21617. X        report_progress (report, 
  21618. X                 tsprintf ("\nprocess_live_request(): \
  21619. Xrecv(): unexpected char %c", ch), TRUE);
  21620. X    else if (value < 0 && errno && errno != EWOULDBLOCK &&
  21621. X         errno != EAGAIN && errno != EINTR && errno != EINVAL)
  21622. X      report_progress (report,
  21623. X                 tsprintf ("\nprocess_live_request(): \
  21624. Xrecv() failed: errno %d", errno), TRUE);
  21625. X    while (recv (msg_sock, &ch, 1, MSG_OOB) > 0);
  21626. X    SET_BLOCKING ("process_live_request");
  21627. X# endif
  21628. X# ifdef bsd
  21629. X    sigsetmask (sig_mask);
  21630. X# elif defined (svr4) || defined (svr3)
  21631. X    sigrelse (SIGALRM);
  21632. X    sigrelse (TIMEOUT_SIG);
  21633. X# endif
  21634. X      }
  21635. X    }
  21636. X  }
  21637. X  abort:
  21638. X  REPLY (msg_sock, CONN_CLOSED, strlen (GOOD_BYE));
  21639. X  write_to_fd (msg_sock, GOOD_BYE, strlen (GOOD_BYE));
  21640. X  ciao:
  21641. X  free ((char *) buf);
  21642. X  free ((char *) passwd);
  21643. X  unlink (mailforwardf);
  21644. X  unlink (replyf);
  21645. X  unlink (requests_file);
  21646. X  close (msg_sock);
  21647. X# ifndef SYSLOG
  21648. X  fclose (report);
  21649. X# endif
  21650. X  _exit (0);
  21651. X}
  21652. X
  21653. X/*
  21654. X  Check for redirection to a file; return TRUE if no errors, FALSE otherwise.
  21655. X  The file to written to (if any) will be stored in 'outfile' and 'fmode'
  21656. X  will be set.
  21657. X*/
  21658. X
  21659. XBOOLEAN check_for_redirection (char *buf, char *outfile, int *fmode,
  21660. X                   int msg_sock, BOOLEAN bin)
  21661. X{
  21662. X  char *s = buf, *b = buf, *r, reply [MAX_LINE];
  21663. X  int i, nquote = 0, nch;
  21664. X  extern int literal;
  21665. X
  21666. X  RESET (outfile);
  21667. X  *fmode = 0;
  21668. X  while (*s != EOS) {
  21669. X    prevch (s, b);
  21670. X    if (!nquote) {
  21671. X      if (literal)
  21672. X    *(s - 1) = *s,
  21673. X    *s = (char) 0x1;
  21674. X      else if (*s == '\'')
  21675. X    nquote = 1;
  21676. X      else if (*s == '"')
  21677. X    nquote = 2;
  21678. X      else if (*s == '>') {
  21679. X    if (!literal && outfile[0] == EOS) {
  21680. X      nch = nextch (s);
  21681. X      sscanf (s + (nch != '>' ? 1 : 2), "%s", outfile);
  21682. X      if (outfile [0] == EOS) {
  21683. X        REPLY (msg_sock, SYNTAX_ERROR, strlen (NULL_REDIRECT) +
  21684. X           strlen (PROMPT));
  21685. X        if (write_to_fd (msg_sock, NULL_REDIRECT, strlen (NULL_REDIRECT)) < 0)
  21686. X          CLIENT_LOST (13);
  21687. X        return FALSE;
  21688. X      }
  21689. X      else {
  21690. X        *fmode = (bin ? WRITE_TO_FILE_BIN : WRITE_TO_FILE_ASC);
  21691. X        if (nch == '>')
  21692. X          *fmode = (bin ? APPEND_TO_FILE_BIN : APPEND_TO_FILE_ASC);
  21693. X        r = s + 1; /* Remove > or >> and file name */
  21694. X        if (nch == '>') ++r;
  21695. X        while (*r != EOS && (*r == ' ' || *r == '\t')) ++r;
  21696. X        while (*r != EOS && !isspace (*r)) ++r;
  21697. X        sprintf (s, "%s", r);
  21698. X        --s;
  21699. X      }
  21700. X    }
  21701. X      }
  21702. X    }
  21703. X    else if ((nquote == 1 && *s == '\'') ||
  21704. X         (nquote == 2 && *s == '"')) {
  21705. X      if (!literal)
  21706. X    nquote = 0;
  21707. X      else
  21708. X    *(s - 1) = *s,
  21709. X    *s = (char) 0x1;
  21710. X    }
  21711. X    ++s;
  21712. X  }
  21713. X  for (s = buf; *s != EOS; ++s)
  21714. X    if (*s == 0x1)
  21715. X      sprintf (s, "%s", s + 1),
  21716. X      --s;
  21717. X  return TRUE;
  21718. X}
  21719. X
  21720. X/*
  21721. X  Return TRUE if the file is writeable on the client side, FALSE otherwise.
  21722. X*/
  21723. X
  21724. XBOOLEAN writeable_file (char *outfile, int msg_sock)
  21725. X{
  21726. X  char reply [MAX_LINE];
  21727. X  int i = 0, err;
  21728. X
  21729. X  REPLY_FILE (msg_sock, TEST_FILE_PERMISSIONS, 0, outfile);
  21730. X  errno = 0;
  21731. X  while (read (msg_sock, reply, 3) < 0 && (errno == EINTR
  21732. X# ifdef ERESTART
  21733. X     || errno == ERESTART)
  21734. X# else
  21735. X                       )
  21736. X# endif
  21737. X     ) {
  21738. X    i = sizeof (err);
  21739. X    if (!getsockopt (sock_fd, SOL_SOCKET, SO_ERROR, (char *) &err, (int *) &i)) {
  21740. X      if (err)
  21741. X    CLIENT_LOST (13);
  21742. X    }
  21743. X    else {
  21744. X      REPLY (msg_sock, SYS_ERROR, strlen (REMOTE_SYS_ERROR));
  21745. X      write_to_fd (msg_sock, REMOTE_SYS_ERROR, strlen (REMOTE_SYS_ERROR));
  21746. X      CLIENT_LOST (13);
  21747. X    }
  21748. X    errno = 0;
  21749. X  }
  21750. X  if (errno && errno != EINTR
  21751. X# ifdef ERESTART
  21752. X      && errno != ERESTART
  21753. X# endif
  21754. X      ) {
  21755. X    CLIENT_LOST (13);
  21756. X  }
  21757. X  reply [3] = EOS;
  21758. X  if (atoi (reply) == PERMISSION_DENIED) {
  21759. X    REPLY (msg_sock, OK, strlen (PROMPT));
  21760. X    RESET (outfile);
  21761. X    return FALSE;
  21762. X  }
  21763. X  return TRUE;
  21764. X}
  21765. X
  21766. X/*
  21767. X  Return TRUE id 'pid' in in 'clients', FALSE otherwise.
  21768. X*/
  21769. X
  21770. XBOOLEAN child_alive (int pid, CLIENT clients [])
  21771. X{
  21772. X  int i;
  21773. X
  21774. X  for (i = 0; i < nforks; i++)
  21775. X    if (clients[i].pid == pid)
  21776. X      return TRUE;
  21777. X  return FALSE;
  21778. X}
  21779. X
  21780. X/*
  21781. X  Return TRUE if we are currently delivering mail, FALSE otherwise.
  21782. X*/
  21783. X
  21784. XBOOLEAN still_delivering_mail (int sid)
  21785. X{
  21786. X  int i = semctl (sid, 0, GETVAL);
  21787. X
  21788. X  return ((i >= 0 ? i : 0) & SEM_DLVR_MAIL);
  21789. X}
  21790. X#endif
  21791. *-*-END-of-src/serverd.c-*-*
  21792. echo x - src/signals.c
  21793. sed 's/^X//' >src/signals.c <<'*-*-END-of-src/signals.c-*-*'
  21794. X/*
  21795. X  ----------------------------------------------------------------------------
  21796. X  |                            SIGNAL FUNCTIONS                              |
  21797. X  |                                                                          |
  21798. X  |                              Version 2.2                                 |
  21799. X  |                                                                          |
  21800. X  |                (or, when Computer Science gets to you)                   |
  21801. X  |                                                                          |
  21802. X  |                    Written by Anastasios Kotsikonas                      |
  21803. X  |                           (tasos@cs.bu.edu)                              |
  21804. X  |                                                                          |
  21805. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  21806. X  | whole and not in parts, as long as you do not remove or alter the author |
  21807. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  21808. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  21809. X  | provided for your personal use, you may not alter the functions         |
  21810. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  21811. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  21812. X  | any changes you may have made. No part of the source code bearing a         |
  21813. X  | copyright notice can be included in commercial software systems without  |
  21814. X  | written permission by the author.                         |
  21815. X  | By using this software you are bound by this agreement.                  |
  21816. X  | This software comes with no warranties and cannot be sold for profit.    |
  21817. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  21818. X  | files when distributing this software.                                   |
  21819. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  21820. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  21821. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  21822. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  21823. X  | (ii).                                                                    |
  21824. X  ----------------------------------------------------------------------------
  21825. X*/
  21826. X
  21827. X#include <stdio.h>
  21828. X#include <signal.h>
  21829. X#ifndef unknown_port
  21830. X# ifndef __NeXT__
  21831. X#  include <unistd.h>
  21832. X# else
  21833. X#  include <libc.h>
  21834. X# endif
  21835. X#endif
  21836. X#include "defs.h"
  21837. X#include "struct.h"
  21838. X
  21839. X#include <errno.h>
  21840. X#ifdef unknown_port
  21841. Xextern int errno;
  21842. X#endif
  21843. X
  21844. X#ifdef GO_INTERACTIVE
  21845. X# include <sys/types.h>
  21846. X# include <sys/ipc.h>
  21847. X# include <sys/sem.h>
  21848. X#endif
  21849. X
  21850. X#ifdef __STDC__
  21851. X# include <stdarg.h>
  21852. Xextern int  syscom (char *, ...);
  21853. Xextern char *tsprintf (char *, ...);
  21854. X#else
  21855. X# include <varargs.h>
  21856. Xextern int  syscom ();
  21857. Xextern char *tsprintf ();
  21858. X#endif
  21859. Xextern void report_progress (FILE *, char *, int);
  21860. Xextern char *extract_filename (char *);
  21861. Xextern int  gexit (int);
  21862. X
  21863. Xvoid   init_signals (void);
  21864. Xvoid   catch_signals (void);
  21865. Xvoid   my_abort (int);
  21866. X
  21867. Xstatic char *signals[MAX_SIGNAL + 1];   /* Signal names */
  21868. X
  21869. X/*
  21870. X  Initialize the signals[].
  21871. X*/
  21872. X
  21873. Xvoid init_signals ()
  21874. X{
  21875. X  signals[SIGILL] = "SIGILL";
  21876. X  signals[SIGQUIT] = "SIGQUIT";
  21877. X  signals[SIGTERM] = "SIGTERM";
  21878. X#ifdef SIGBUS
  21879. X  signals[SIGBUS] = "SIGBUS";
  21880. X#endif
  21881. X  signals[SIGSEGV] = "SIGSEGV";
  21882. X  signals[SIGKILL] = "SIGKILL";
  21883. X}
  21884. X
  21885. X/*
  21886. X  Catch signals to print messages before aborting.
  21887. X*/
  21888. X
  21889. Xvoid catch_signals ()
  21890. X{
  21891. X#ifdef _AIX
  21892. X  struct sigaction s;
  21893. X#endif
  21894. X  
  21895. X#ifdef SIGTSTP
  21896. X  signal (SIGTSTP, SIG_IGN);
  21897. X#endif
  21898. X#ifdef SIGTTIN
  21899. X  signal (SIGTTIN, SIG_IGN);
  21900. X#endif
  21901. X#ifdef SIGTTOU
  21902. X  signal (SIGTTOU, SIG_IGN);
  21903. X#endif
  21904. X  signal (SIGHUP, SIG_IGN);
  21905. X  signal (SIGILL, my_abort);
  21906. X  signal (SIGQUIT, my_abort);
  21907. X  signal (SIGTERM, my_abort);
  21908. X  signal (SIGSEGV, my_abort);
  21909. X#ifdef SIGBUS
  21910. X  signal (SIGBUS, my_abort);
  21911. X#endif
  21912. X  signal (SIGKILL, my_abort); /* Can't be caught, but why not try? */
  21913. X#ifdef _AIX
  21914. X  s.sa_handler = my_abort;
  21915. X  s.sa_mask.losigs = s.sa_mask.hisigs = 0;
  21916. X  s.sa_flags = SA_FULLDUMP;
  21917. X  sigaction (SIGSEGV, &s, (struct sigaction *) NULL);
  21918. X  sigaction (SIGILL, &s, (struct sigaction *) NULL);
  21919. X  sigaction (SIGQUIT, &s, (struct sigaction *) NULL);
  21920. X  sigaction (SIGBUS, &s, (struct sigaction *) NULL); 
  21921. X#endif
  21922. X}
  21923. X
  21924. X/*
  21925. X  Kill program after sending message to MANAGER that this is
  21926. X  about to happen (message is sent only when using UCB mail).
  21927. X*/
  21928. X
  21929. Xvoid my_abort (int sig)
  21930. X{
  21931. X  extern SYS sys;
  21932. X  extern char *prog;
  21933. X  extern FILE *report;
  21934. X  extern int sid;
  21935. X  char *s;
  21936. X
  21937. X  signal (sig, SIG_IGN);
  21938. X  report_progress (report, tsprintf ("\n*** %s: Received %s signal ***\n",
  21939. X                     (prog ? prog : "???"),
  21940. X                     signals[sig]), -TRUE);
  21941. X  if (sys.options & BSD_MAIL)
  21942. X    syscom ("echo '' | %s -s '%s received %s' %s &", UCB_MAIL,
  21943. X        (prog ? prog : "???"), signals[sig], sys.manager);
  21944. X  if (sig == SIGQUIT || sig == SIGILL || sig == SIGSEGV
  21945. X#ifdef SIGBUS
  21946. X      || sig == SIGBUS
  21947. X#endif
  21948. X     ) {
  21949. X#ifdef GO_INTERACTIVE
  21950. X  union semun {
  21951. X    int val;
  21952. X    struct semid_ds *buf;
  21953. X    ushort *array;
  21954. X  } sembuf;
  21955. X  sembuf.val = 0;
  21956. X  /* Reset flag so that serverd will not wait for ever. */
  21957. X  if (sid >= 0 && semctl (sid, 0, SETVAL, sembuf) < 0)
  21958. X    report_progress (report, tsprintf ("\ngexit(): Error semctl(); errno %d", 
  21959. X                       errno), TRUE);
  21960. X#endif
  21961. X    if (prog)
  21962. X      s = extract_filename (prog),
  21963. X#ifdef __STDC__
  21964. X      syscom ("rm -f %s/core; touch %s/core.%s; ln -s %s/core.%s %s/core",
  21965. X          PATH, PATH, s, PATH, s, PATH),
  21966. X#else
  21967. X      syscom ("rm -f %s/core; touch %s/core.%s; ln -s %s/core.%s %s/core",
  21968. X          PATH", PATH", s, PATH", s, PATH"),
  21969. X#endif
  21970. X      abort ();
  21971. X  }
  21972. X  gexit (8);
  21973. X}
  21974. *-*-END-of-src/signals.c-*-*
  21975. echo x - src/silp.c
  21976. sed 's/^X//' >src/silp.c <<'*-*-END-of-src/silp.c-*-*'
  21977. X/*
  21978. X  ----------------------------------------------------------------------------
  21979. X  |                 SYSTEM INTERACTIVE LISTPROCESSOR CLIENT                  |
  21980. X  |                                         |
  21981. X  |                  Version 1.1                     |
  21982. X  |                                                                          |
  21983. X  |                (or, when Computer Science gets to you)                   |
  21984. X  |                                                                          |
  21985. X  |                    Written by Anastasios Kotsikonas                      |
  21986. X  |                           (tasos@cs.bu.edu)                              |
  21987. X  |                                                                          |
  21988. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  21989. X  | whole and not in parts, as long as you do not remove or alter the author |
  21990. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  21991. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  21992. X  | provided for your personal use, you may not alter the functions          |
  21993. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  21994. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  21995. X  | any changes you may have made. No part of the source code bearing a         |
  21996. X  | copyright notice can be included in commercial software systems without  |
  21997. X  | written permission by the author.                         |
  21998. X  | By using this software you are bound by this agreement.             |
  21999. X  | This software comes with no warranties and cannot be sold for profit.    |
  22000. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  22001. X  | files when distributing this software.                                   |
  22002. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  22003. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  22004. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  22005. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  22006. X  | (ii).                                                                    |
  22007. X  ----------------------------------------------------------------------------
  22008. X
  22009. X  This is a copy of the ilp client (ilp.c) ported for internal use by listproc
  22010. X  for connections to remote servers while processing requests for remote lists.
  22011. X
  22012. X  Refer to the man page (ilp.1) or ilp.c for more information.
  22013. X
  22014. X  PLEASE DO NOT MODIFY THESE ROUTINES AS YOU MAY BREAK THE PROTOCOL AND CREATE
  22015. X  HAVOC WITH PEER INTERACTIVE LISTPROCESSORS. A LOT OF UNDOCUMENTED
  22016. X  ASSUMPTIONS ARE MADE. YOU SHOULD CONTACT ME ABOUT ANY CHANGES YOU WISH TO
  22017. X  MAKE.
  22018. X*/
  22019. X
  22020. X#include <signal.h>
  22021. X#include "defs.h"
  22022. X#undef     NSIG
  22023. X#ifdef GO_INTERACTIVE
  22024. X# include <stdio.h>
  22025. X# include <sys/types.h>
  22026. X# include <string.h>
  22027. X# if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
  22028. X && !defined (sequent) && !defined (unknown_port)
  22029. X# include <malloc.h>
  22030. X# endif
  22031. X# ifndef unknown_port
  22032. X#  ifndef __NeXT__
  22033. X#   include <unistd.h>
  22034. X#  else
  22035. X#   include <libc.h>
  22036. X#  endif
  22037. X# endif
  22038. X# if defined (stardent) || defined (stellar) || defined (titan)
  22039. X#  include <rpc/types.h>
  22040. X# endif
  22041. X# include <sys/stat.h>
  22042. X# include <fcntl.h>
  22043. X# include <errno.h>
  22044. X#ifdef unknown_port
  22045. Xextern int errno;
  22046. X#endif
  22047. X# include <sys/socket.h>
  22048. X# include <netinet/in.h>
  22049. X# include <netdb.h>
  22050. X# include <sys/file.h>
  22051. X# include <sys/ioctl.h>
  22052. X# if defined (sco) || defined (M_XENIX) || defined (M_UNIX)
  22053. X#  include <sys/stropts.h>
  22054. X# endif
  22055. X# if (defined (sco) || defined (M_XENIX) || defined (M_UNIX)) && \
  22056. X  defined (HAVE_SELECT_H)
  22057. X#  include <sys/times.h>
  22058. X# else
  22059. X#  include <sys/time.h>
  22060. X# endif
  22061. X# ifdef HAVE_SETJMP_H
  22062. X#  include <setjmp.h>
  22063. X# endif
  22064. X# ifdef HAVE_SELECT_H
  22065. X#  include <sys/select.h>
  22066. X# endif
  22067. X# ifdef HAVE_ULIMIT_H
  22068. X#  include <ulimit.h>
  22069. X# endif
  22070. X# include "ilp.h"
  22071. X
  22072. X# ifndef UL_GDESLIM
  22073. X#  define UL_GDESLIM    4
  22074. X# endif
  22075. X
  22076. X# ifndef FD_SET          /* for 4.2BSD */
  22077. X#  define FD_SETSIZE      (sizeof(fd_set) * 8)
  22078. X#  define FD_SET(n, p)    (((fd_set *) (p))->fds_bits[0] |= (1 << ((n) % 32)))
  22079. X#  define FD_CLR(n, p)    (((fd_set *) (p))->fds_bits[0] &= ~(1 << ((n) % 32)))
  22080. X#  define FD_ISSET(n, p)  (((fd_set *) (p))->fds_bits[0] & (1 << ((n) % 32)))
  22081. X#  define FD_ZERO(p)      memset ((char *)(p), '\0', sizeof(*(p)))
  22082. X# endif
  22083. X
  22084. X# ifndef __NeXT__
  22085. Xextern    long int atoi (char *);
  22086. X# else
  22087. Xextern    int atoi (const char *);
  22088. X# endif
  22089. Xextern  long int write_to_fd (int, char *, long int);
  22090. Xextern  void report_progress (FILE *, char *, BOOLEAN);
  22091. Xextern  char *upcase (char *);
  22092. Xextern    char *_strstr (char *, char *);
  22093. X
  22094. Xextern  FILE *report;
  22095. X
  22096. Xint     ilp_server_response (int, int);
  22097. Xint      connect_to_ilp_server (char *, int);
  22098. Xint     sighandle (int);
  22099. Xint     urg_data (int);
  22100. Xint     alarm_clock (int);
  22101. Xlong int read_from_fd (int, long int, int, int);
  22102. Xint     open_file (char *, int, int);
  22103. Xint      check_server_response (int, char *, int);
  22104. Xint     check_for_redirection (char *, char *);
  22105. X
  22106. Xlong int nbytes, sock_fd;
  22107. Xint  to_file, prompt_len, ofd, check_sio, append_output = 0, timed_out;
  22108. Xchar args [256];
  22109. Xvoid (*f1)(), (*f2)(), (*f3)();
  22110. X# ifdef HAVE_SETJMP_H
  22111. Xjmp_buf env;
  22112. X# endif
  22113. X
  22114. X#else
  22115. X# include "ilpp.h"
  22116. X#endif
  22117. X
  22118. X#ifdef __STDC__
  22119. X# include <stdarg.h>
  22120. Xint     silp (char *, int, char *, char *, int, char *, char *, ...);
  22121. Xextern  char *tsprintf (char *, ...);
  22122. X#else
  22123. X# include <varargs.h>
  22124. Xint     silp ();
  22125. Xextern  char *tsprintf ();
  22126. X#endif
  22127. X
  22128. X/*
  22129. X  Main function. Connect to server, issue requests and receive replies.
  22130. X
  22131. X  Returns: an ILPP code or -1 on error.
  22132. X*/
  22133. X
  22134. X#ifdef __STDC__
  22135. Xint silp (char *Host, int port, char *Login, char *Passwd,
  22136. X      int response_timeout, char *outfile, char *control, ...)
  22137. X#else
  22138. Xint silp (Host, port, Login, Passwd, response_timeout, outfile, control,
  22139. X      va_alist)
  22140. Xchar *Host, *outfile, *Login, *Passwd, *control;
  22141. Xint port, response_timeout;
  22142. Xva_dcl
  22143. X#endif
  22144. X{
  22145. X#ifndef GO_INTERACTIVE
  22146. X  return SYS_ERROR;
  22147. X#else
  22148. X  char *buf, *tmp, infile [256], wbuf [256], *sep = "IUL:", *s, *r, rhost [256];
  22149. X  char login [256], passwd [256], host [256], raddr [256], taddr [256];
  22150. X  char version [80];
  22151. X  int cmd, i, sprompt_len, timeout, rfd, bytes_alloced = 0, naddr, naddr2,
  22152. X    _prompt_len, rtc = response_timeout;
  22153. X  struct stat stat_buf;
  22154. X  struct hostent *hp, *thp;
  22155. X  struct in_addr _addr;
  22156. X  va_list ap;
  22157. X
  22158. X
  22159. X  check_sio = 0;
  22160. X  strncpy (login, Login, 255);
  22161. X  strncpy (passwd, Passwd, 255);
  22162. X  strncpy (host, Host, 255);
  22163. X  login [255] = passwd [255] = host [255] = EOS;
  22164. X  if ((ofd = open (outfile, O_CREAT | O_WRONLY | O_APPEND, 0600)) < 0) {
  22165. X    report_progress (report, tsprintf ("\nsilp(): Cannot open %s", outfile),
  22166. X             TRUE);
  22167. X    return -1;
  22168. X  }
  22169. X  bytes_alloced = 256;
  22170. X  if ((buf = (char *) malloc (bytes_alloced * sizeof (char))) == NULL) {
  22171. X    report_progress (report, "\nsilp(): malloc() failed", TRUE);
  22172. X    close (ofd);
  22173. X    return -1;
  22174. X  }
  22175. X
  22176. X# ifdef HAVE_SETJMP_H
  22177. X#  ifdef SIGIO
  22178. X  f1 = (void (*)()) signal (SIGIO, (void (*)()) urg_data);
  22179. X#  endif
  22180. X#  ifdef SIGURG
  22181. X  f2 = (void (*)()) signal (SIGURG, (void (*)()) urg_data);
  22182. X#  endif
  22183. X  f3 = (void (*)()) signal (SIGPIPE, (void (*)()) sighandle);
  22184. X# endif
  22185. X# ifdef __STDC__
  22186. X  va_start (ap, control);
  22187. X# else
  22188. X  va_start (ap);
  22189. X# endif
  22190. X
  22191. X  upcase (login);
  22192. X  s = login;
  22193. X  i = 0;
  22194. X  while (i < MAX_HOPS && (s = _strstr (s, sep)))
  22195. X    ++i,
  22196. X    ++s;
  22197. X  if (i >= MAX_HOPS) {
  22198. X    write_to_fd (ofd, "Too many hops.\n", 15);
  22199. X    cmd = PEER_UNAVAIL;
  22200. X    goto abort;
  22201. X  }
  22202. X  s = login;
  22203. X  upcase (host);
  22204. X  while ((s = _strstr (s, sep))) {    /* Check for loop */
  22205. X    s += 4;   /* Point to remote host */
  22206. X    sscanf (s, "%s", rhost);
  22207. X    if ((r = strchr (rhost, ';')))
  22208. X      *r = EOS;
  22209. X    thp = hp = gethostbyname (host);
  22210. X    if (hp) { /* Just got IP address(es) of host */
  22211. X      if ((thp = (struct hostent *) malloc (sizeof (struct hostent))) == NULL) {
  22212. X    report_progress (report, "\nsilp(): malloc() failed", TRUE);
  22213. X    close (ofd);
  22214. X    return -1;
  22215. X      }
  22216. X      memcpy ((char *) thp, (char *) hp, sizeof (*hp));
  22217. X#ifdef h_addr
  22218. X      naddr = 0;
  22219. X      if ((thp->h_addr_list = (char **) malloc (sizeof (char *))) == NULL) {
  22220. X    report_progress (report, "\nsilp(): malloc() failed", TRUE);
  22221. X    close (ofd);
  22222. X    return -1;
  22223. X      }
  22224. X      while (hp->h_addr_list[naddr]) { /* Copy all IP addresses */
  22225. X    if ((thp->h_addr_list = (char **)
  22226. X         realloc (thp->h_addr_list, (naddr + 2) * sizeof (char *))) == NULL) {
  22227. X      report_progress (report, "\nsilp(): realloc() failed", TRUE);
  22228. X      close (ofd);
  22229. X      return -1;
  22230. X    }
  22231. X    if ((thp->h_addr_list[naddr] =
  22232. X         (char *) malloc (thp->h_length * sizeof (char))) == NULL) {
  22233. X      report_progress (report, "\nsilp(): malloc() failed", TRUE);
  22234. X      close (ofd);
  22235. X      return -1;
  22236. X    }
  22237. X    memcpy ((char *) thp->h_addr_list[naddr],
  22238. X        (char *) hp->h_addr_list[naddr], hp->h_length);
  22239. X    thp->h_addr_list[++naddr] = NULL;
  22240. X      }
  22241. X      naddr = 0;
  22242. X      while (thp->h_addr_list[naddr]) { /* For all target addresses */
  22243. X    memcpy ((char *) &_addr, (char *) thp->h_addr_list[naddr++],
  22244. X        thp->h_length);
  22245. X    strcpy (taddr, (char *) inet_ntoa (_addr));
  22246. X    hp = gethostbyname (rhost);
  22247. X    naddr2 = 0;
  22248. X    while (hp && hp->h_addr_list[naddr2]) { /* Check all hosts visited */
  22249. X      memcpy ((char *) &_addr, (char *) hp->h_addr_list[naddr2++],
  22250. X          hp->h_length);
  22251. X      strcpy (raddr, (char *) inet_ntoa (_addr));
  22252. X      if (!strcmp (taddr, raddr)) { /* Loop */
  22253. X        write_to_fd (ofd, "Loop detected.\n", 15);
  22254. X        cmd = PEER_UNAVAIL;
  22255. X        goto abort;
  22256. X      }
  22257. X    }
  22258. X    /* Assume gethostbyname() failed */
  22259. X    if (!strcmp (host, rhost) || !strcmp (taddr, rhost)) { /* Loop !!! */
  22260. X      write_to_fd (ofd, "Loop detected.\n", 15);
  22261. X      cmd = PEER_UNAVAIL;
  22262. X      goto abort;
  22263. X    }
  22264. X      }
  22265. X      naddr = 0;
  22266. X      while (thp->h_addr_list[naddr])
  22267. X    free ((char *) thp->h_addr_list[naddr++]);
  22268. X      free ((char **) thp->h_addr_list);
  22269. X#else
  22270. X      if ((thp->h_addr = (char *) malloc ((strlen (hp->h_addr) + 1) *
  22271. X                      sizeof (char))) == NULL) {
  22272. X    report_progress (report, "\nsilp(): malloc() failed", TRUE);
  22273. X    close (ofd);
  22274. X    return -1;
  22275. X      }
  22276. X      memcpy ((char *) thp->h_addr, (char *) hp->h_addr, hp->h_length);
  22277. X      memcpy ((char *) &_addr, (char *) thp->h_addr, thp->h_length);
  22278. X      strcpy (taddr, (char *) inet_ntoa (_addr));
  22279. X      hp = gethostbyname (rhost);
  22280. X      memcpy ((char *) &_addr, (char *) hp->h_addr, hp->h_length);
  22281. X      strcpy (raddr, (char *) inet_ntoa (_addr));
  22282. X      if (!strcmp (taddr, raddr)) { /* Loop */
  22283. X    write_to_fd (ofd, "Loop detected.\n", 15);
  22284. X    cmd = PEER_UNAVAIL;
  22285. X    goto abort;
  22286. X      }
  22287. X      free ((char *) thp->h_addr);
  22288. X#endif
  22289. X      free ((struct hostent *) thp);
  22290. X    }
  22291. X    else { /* Host is an IP address */
  22292. X      naddr = 0;
  22293. X      hp = gethostbyname (rhost);
  22294. X#ifdef h_addr
  22295. X      while (hp && hp->h_addr_list[naddr]) { /* Check all hosts visited */
  22296. X    memcpy ((char *) &_addr, (char *) hp->h_addr_list[naddr++],
  22297. X        hp->h_length);
  22298. X    strcpy (raddr, (char *) inet_ntoa (_addr));
  22299. X    if (!strcmp (raddr, host)) { /* Loop */
  22300. X      write_to_fd (ofd, "Loop detected.\n", 15);
  22301. X      cmd = PEER_UNAVAIL;
  22302. X      goto abort;
  22303. X    }
  22304. X      }
  22305. X#else
  22306. X      memcpy ((char *) &_addr, (char *) hp->h_addr, hp->h_length);
  22307. X      strcpy (raddr, (char *) inet_ntoa (_addr));
  22308. X      if (!strcmp (raddr, host)) { /* Loop */
  22309. X    write_to_fd (ofd, "Loop detected.\n", 15);
  22310. X    cmd = PEER_UNAVAIL;
  22311. X    goto abort;
  22312. X      }
  22313. X#endif
  22314. X    }
  22315. X  }
  22316. X
  22317. X  if ((sock_fd = connect_to_ilp_server (host, port)) < 0)
  22318. X    if ((sock_fd = connect_to_ilp_server (host, (((port & 0xff00) >> 8) |
  22319. X     ((port & 0xff) << 8)))) < 0) {
  22320. X      write_to_fd (ofd, "Could not connect to host.\n", 27);
  22321. X      cmd = PEER_UNAVAIL;
  22322. X      goto abort;
  22323. X    }
  22324. X
  22325. X  if ((cmd = ilp_server_response (sock_fd, response_timeout)) != CONNECT) {
  22326. X    write_to_fd (ofd, "Handshake failed, not an interactive ListProcessor \
  22327. Xserver.\n", 59);
  22328. X    cmd = SYS_ERROR;
  22329. X    goto abort;
  22330. X  }
  22331. X
  22332. X# ifdef HAVE_SETJMP_H
  22333. X  if (!setjmp (env)) {    /* No signal; proceed */
  22334. X# endif
  22335. X
  22336. X  if (check_server_response (cmd, args, response_timeout))
  22337. X# ifdef HAVE_SETJMP_H
  22338. X    longjmp (env, 1);
  22339. X# else
  22340. X    goto abort;
  22341. X# endif
  22342. X  if ((timeout = nbytes) < response_timeout)
  22343. X    response_timeout = timeout;
  22344. X  sscanf (args, "%s %d %d\n", version, &_prompt_len, &sprompt_len);
  22345. X
  22346. X  if ((cmd = ilp_server_response (sock_fd, response_timeout)) < 0)
  22347. X# ifdef HAVE_SETJMP_H
  22348. X    longjmp (env, 1);
  22349. X# else
  22350. X    goto abort;
  22351. X# endif
  22352. X  check_server_response (cmd, args, response_timeout);
  22353. X  if (cmd == CONN_CLOSED || cmd == SERVER_BUSY || cmd == PEER_UNAVAIL ||
  22354. X      cmd == CONN_ABORTED || cmd == SYS_ERROR || cmd == CONN_TIMEOUT)
  22355. X    append_output = 1;
  22356. X  if (read_from_fd (sock_fd, nbytes, response_timeout, ofd) < 0)
  22357. X# ifdef HAVE_SETJMP_H
  22358. X    longjmp (env, 1);
  22359. X# else
  22360. X    goto abort;
  22361. X# endif
  22362. X  if (cmd == CONN_CLOSED || cmd == SERVER_BUSY || cmd == PEER_UNAVAIL ||
  22363. X      cmd == CONN_ABORTED || cmd == SYS_ERROR || cmd == CONN_TIMEOUT)
  22364. X# ifdef HAVE_SETJMP_H
  22365. X    longjmp (env, 1);
  22366. X# else
  22367. X    goto abort;
  22368. X# endif
  22369. X  prompt_len = _prompt_len;
  22370. X  strcat (login, "\n");
  22371. X  if (write_to_fd (sock_fd, login, strlen (login)) < 0)
  22372. X# ifdef HAVE_SETJMP_H
  22373. X    longjmp (env, 1);
  22374. X# else
  22375. X    goto abort;
  22376. X# endif
  22377. X  if ((cmd = ilp_server_response (sock_fd, response_timeout)) < 0)
  22378. X# ifdef HAVE_SETJMP_H
  22379. X    longjmp (env, 1);
  22380. X# else
  22381. X    goto abort;
  22382. X# endif
  22383. X  if (check_server_response (cmd, args, response_timeout))
  22384. X# ifdef HAVE_SETJMP_H
  22385. X    longjmp (env, 1);
  22386. X# else
  22387. X    goto abort;
  22388. X# endif
  22389. X  if (cmd == PASSWORD_REQUIRED) {
  22390. X    strcat (passwd, "\n");
  22391. X    if (write_to_fd (sock_fd, passwd, strlen (passwd)) < 0)
  22392. X# ifdef HAVE_SETJMP_H
  22393. X      longjmp (env, 1);
  22394. X# else
  22395. X      goto abort;
  22396. X# endif
  22397. X  }
  22398. X  else if (cmd == PEER_UNAVAIL)
  22399. X# ifdef HAVE_SETJMP_H
  22400. X    longjmp (env, 1);
  22401. X# else
  22402. X    goto abort;
  22403. X# endif
  22404. X
  22405. X  RESET (buf);
  22406. X  vsprintf (buf, control, ap);
  22407. X  va_end (ap);
  22408. X  strcat (buf, "\n__abort__\n");    /* Just in case */
  22409. X  while (cmd != CONN_CLOSED && cmd != CONN_ABORTED && cmd != CONN_TIMEOUT) {
  22410. X    check_sio = 0;
  22411. X    if ((cmd = ilp_server_response (sock_fd, response_timeout)) < 0) break;
  22412. X    if (check_server_response (cmd, args, response_timeout)) break;
  22413. X    if (cmd == TEST_FILE_PERMISSIONS) continue;
  22414. X    if (cmd != CONN_ABORTED && cmd != CONN_TIMEOUT)
  22415. X      if (read_from_fd (sock_fd, nbytes, response_timeout,
  22416. X            (cmd != MESSAGE ? ofd : 0)) < 0) break;
  22417. X    if (cmd == MESSAGE) {
  22418. X      response_timeout -= 10;
  22419. X      if (response_timeout <= 0)
  22420. X    response_timeout = 1;
  22421. X      continue;
  22422. X    }
  22423. X    check_sio = ! (append_output = 0);
  22424. X    if (cmd != CONN_CLOSED && cmd != CONN_ABORTED && cmd != CONN_TIMEOUT) {
  22425. X      response_timeout = rtc;
  22426. X      if (buf [0] == EOS) {
  22427. X        RESET (infile);
  22428. X        if ((rfd = check_for_redirection (buf, infile)) < 0)
  22429. X      strcpy (buf, "\n");
  22430. X        if (rfd >= 0 && infile [0] != EOS) { /* Input redirection */
  22431. X      fstat (rfd, &stat_buf);
  22432. X      if (!(stat_buf.st_mode & S_IFREG)) {
  22433. X        printf ("%s: Not a regular file\n", infile);
  22434. X        strcpy (buf, "\n");
  22435. X        goto skip;
  22436. X      }
  22437. X      if ((stat_buf.st_size + strlen (buf) + 2) > bytes_alloced) {
  22438. X        bytes_alloced = stat_buf.st_size + strlen (buf) + 2;
  22439. X        if ((buf = (char *) realloc (buf, bytes_alloced * sizeof (char))) ==
  22440. X            NULL) {
  22441. X          write_to_fd (ofd, "FATAL: internal memory error.\n", 30);
  22442. X          report_progress (report, "\nsilp(): realloc() failed", TRUE);
  22443. X          cmd = -1;
  22444. X          break;
  22445. X        }
  22446. X      }
  22447. X      i = strlen (buf);
  22448. X      if (read (rfd, &buf [strlen (buf)], stat_buf.st_size) <
  22449. X          stat_buf.st_size) {
  22450. X        write_to_fd (ofd, "FATAL: Failed to read all of the input \
  22451. Xfile.\n", 45);
  22452. X        cmd = -1;
  22453. X        break;
  22454. X      }
  22455. X      buf [i + stat_buf.st_size] = EOS;
  22456. X      if (buf [i + stat_buf.st_size - 1] != '\n')
  22457. X        strcat (&buf [i + stat_buf.st_size], "\n");
  22458. X      close (rfd);
  22459. X        }
  22460. X      }
  22461. X      skip:
  22462. X      strncpy (wbuf, buf, 174);
  22463. X      while (!(tmp = strchr (wbuf, '\n')))
  22464. X    wbuf [174] = '\n';
  22465. X      if (tmp != wbuf) /* Not an empty line */
  22466. X        sprintf (tmp, " >> %s\n", outfile);
  22467. X      check_sio = 0;
  22468. X      if (write_to_fd (sock_fd, wbuf, strlen (wbuf)) < 0) break;
  22469. X      sprintf (buf, "%s", strchr (buf, '\n') + 1);
  22470. X      if (strncmp (wbuf, "quit", 4) && strncmp (wbuf, "exit", 4))
  22471. X    append_output = 1;
  22472. X      if (!strncmp (wbuf, "__abort__", 9)) 
  22473. X    break;
  22474. X    }
  22475. X  }
  22476. X
  22477. X# ifdef HAVE_SETJMP_H
  22478. X  } /* if (!setjmp (env)) ... */
  22479. X  else { /* Return from longjmp () */
  22480. X  }
  22481. X# endif
  22482. X
  22483. X abort:
  22484. X# ifdef HAVE_SETJMP_H
  22485. X#  ifdef SIGIO
  22486. X  signal (SIGIO, (void (*)()) f1);
  22487. X#  endif
  22488. X#  ifdef SIGURG
  22489. X  signal (SIGURG, (void (*)()) f2);
  22490. X#  endif
  22491. X  signal (SIGPIPE, (void (*)()) f3);
  22492. X# endif
  22493. X  signal (SIGALRM, SIG_IGN);
  22494. X  if (sock_fd >= 0)
  22495. X    close (sock_fd);
  22496. X  close (ofd);
  22497. X  if (buf)
  22498. X    free ((char *) buf);
  22499. X  return cmd;
  22500. X#endif
  22501. X}
  22502. X
  22503. X#ifdef GO_INTERACTIVE
  22504. X/*
  22505. X  Get server response. Store in 'nbytes' the number of bytes in the actual
  22506. X  message that follows, and in 'args' the (optional) file name.
  22507. X
  22508. X  Returns: the server reply code, CONN_TIMEOUT, CONN_ABORTED, or -1 on 
  22509. X  protocol errors.
  22510. X*/
  22511. X
  22512. Xint ilp_server_response (int sock_fd, int response_timeout)
  22513. X{
  22514. X  char buf [256];
  22515. X  int cmd = -1, i, bytes_to_read = 4, bytes_read = 0, value, nfds;
  22516. X  fd_set rfds;
  22517. X  struct timeval timeout;
  22518. X
  22519. X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
  22520. X  defined (apollo) || defined (unknown_port)
  22521. X  nfds = getdtablesize ();
  22522. X# else
  22523. X  nfds = ulimit (UL_GDESLIM);
  22524. X# endif
  22525. X  memset (buf, EOS, 256);
  22526. X  while (bytes_to_read) {
  22527. X    /* Get server command */
  22528. X    FD_ZERO (&rfds);
  22529. X    do {
  22530. X      FD_SET (sock_fd, &rfds);
  22531. X      timeout.tv_sec  = timeout.tv_usec = response_timeout;
  22532. X      errno = 0;
  22533. X      value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
  22534. X    } while (value == -1 && errno == EINTR);
  22535. X
  22536. X    if (value == 0) {
  22537. X      nbytes = 0;
  22538. X      write_to_fd (ofd, "Server response timeout.\n", 25); 
  22539. X      return CONN_TIMEOUT;
  22540. X    }
  22541. X    else if (value < 0) {
  22542. X      write_to_fd (ofd, "select() failed\n", 16);
  22543. X      return -1;
  22544. X    }
  22545. X
  22546. X    errno = 0;
  22547. X    /* Get server command */
  22548. X    bytes_read = read (sock_fd, &buf [4 - bytes_to_read], bytes_to_read);
  22549. X    if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
  22550. X    errno == ECONNREFUSED) {
  22551. X      nbytes = 0;
  22552. X      return CONN_ABORTED;
  22553. X    }
  22554. X    if (bytes_read > 0)
  22555. X      bytes_to_read -= bytes_read;
  22556. X  }
  22557. X  buf[3] = EOS;
  22558. X  cmd = atoi (buf);
  22559. X  i = 0;
  22560. X  do {        /* Get # of bytes in actual message */
  22561. X    again1:
  22562. X    FD_ZERO (&rfds);
  22563. X    do {
  22564. X      FD_SET (sock_fd, &rfds);
  22565. X      timeout.tv_sec = timeout.tv_usec = response_timeout;
  22566. X      errno = 0;
  22567. X      value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
  22568. X    } while (value == -1 && errno == EINTR);
  22569. X
  22570. X    if (value == 0) {
  22571. X      nbytes = 0;
  22572. X      write_to_fd (ofd, "Server response timeout.\n", 25); 
  22573. X      return CONN_TIMEOUT;
  22574. X    }
  22575. X    else if (value < 0) {
  22576. X      write_to_fd (ofd, "select() failed\n", 16);
  22577. X      return -1;
  22578. X    }
  22579. X
  22580. X    errno = 0;
  22581. X    if (read (sock_fd, &buf[i], 1) < 1) {
  22582. X      if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
  22583. X      errno == ECONNREFUSED) {
  22584. X    nbytes = 0;
  22585. X    return CONN_ABORTED;
  22586. X      }
  22587. X      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
  22588. X    goto again1;
  22589. X      write_to_fd (ofd, "Protocol error in control string.\n", 34);
  22590. X      return -1;
  22591. X    }
  22592. X    i++;
  22593. X  } while (buf[i - 1] != ' ');
  22594. X
  22595. X  buf[i - 1] = EOS;
  22596. X  nbytes = atoi (buf);
  22597. X  RESET (args);
  22598. X  i = 0;
  22599. X  do {        /* Get filename (optional) */
  22600. X    again2:
  22601. X    FD_ZERO (&rfds);
  22602. X    do {
  22603. X      FD_SET (sock_fd, &rfds);
  22604. X      timeout.tv_sec = timeout.tv_usec = response_timeout;
  22605. X      errno = 0;
  22606. X      value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
  22607. X    } while (value == -1 && errno == EINTR);
  22608. X
  22609. X    if (value == 0) {
  22610. X      nbytes = 0;
  22611. X      write_to_fd (ofd, "Server response timeout.\n", 25); 
  22612. X      return CONN_TIMEOUT;
  22613. X    }
  22614. X    else if (value < 0) {
  22615. X      write_to_fd (ofd, "select() failed\n", 16);
  22616. X      return -1;
  22617. X    }
  22618. X
  22619. X    errno = 0;
  22620. X    if (read (sock_fd, &args[i], 1) < 1) {
  22621. X      if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
  22622. X          errno == ECONNREFUSED)
  22623. X        return CONN_ABORTED;
  22624. X      if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
  22625. X        goto again2;
  22626. X      write_to_fd (ofd, "Protocol error in control string.\n", 34);
  22627. X      return -1;
  22628. X    }
  22629. X    ++i;
  22630. X  } while (args[i - 1] != '\n');
  22631. X  args[i - 1]= EOS;
  22632. X  return cmd;
  22633. X}
  22634. X
  22635. X/*
  22636. X  Establish connection with unix-listproc. The socket is marked as
  22637. X  non-blocking.
  22638. X
  22639. X  Returns: the socket file descriptor, or -1 on error.
  22640. X*/
  22641. X
  22642. Xint connect_to_ilp_server (char *host, int port)
  22643. X{
  22644. X  int sock_fd, sendbuf = BUFFSIZ, recvbuf = BUFFSIZ, value = 1, nfds, naddr = 0;
  22645. X  struct sockaddr_in sin;
  22646. X  struct hostent *hostentry;
  22647. X  struct timeval timeout;
  22648. X  fd_set readfds, writefds;
  22649. X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
  22650. X  defined (apollo) || defined (unknown_port)
  22651. X  nfds = getdtablesize ();
  22652. X# else
  22653. X  nfds = ulimit (UL_GDESLIM);
  22654. X# endif
  22655. X  timeout.tv_sec = timeout.tv_usec = 0;
  22656. X  if (!(hostentry = gethostbyname (host))) { /* Host name failed; try IP */
  22657. X    sin.sin_addr.s_addr = inet_addr (host);
  22658. X    if (! (hostentry = gethostbyaddr ((char *) &sin.sin_addr,
  22659. X                      sizeof (struct in_addr),
  22660. X                      AF_INET))) {
  22661. X      write_to_fd (ofd, "Invalid host.\n", 14);
  22662. X      return -1;
  22663. X    }
  22664. X  }
  22665. X
  22666. X  do {
  22667. X    if ((sock_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  22668. X      report_progress (report, "\nconnect_to_ilp_server(): Could not create \
  22669. Xsocket", TRUE);
  22670. X      return -1;
  22671. X    }
  22672. X    if (setsockopt (sock_fd, SOL_SOCKET, SO_SNDBUF, (char *) &sendbuf,
  22673. X            sizeof (sendbuf)) < 0)
  22674. X      report_progress (report, "\nconnect_to_ilp_server(): WARNING: Could not \
  22675. Xset send-buffer size: setsockopt() error", TRUE);
  22676. X    if (setsockopt (sock_fd, SOL_SOCKET, SO_RCVBUF, (char *) &recvbuf,
  22677. X            sizeof (recvbuf)) < 0)
  22678. X      report_progress (report, "\nconnect_to_ilp_server(): WARNING: Could not \
  22679. Xset receive-buffer size: setsockopt() error", TRUE);
  22680. X    if (setsockopt (sock_fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &value,
  22681. X            sizeof (value)) < 0)
  22682. X      report_progress (report, "\nconnect_to_ilp_server(): WARNING: Cannot \
  22683. Xtoggle keep-alive connections: setsockopt() error", TRUE);
  22684. X
  22685. X#ifdef h_addr
  22686. X    memcpy ((char *) &sin.sin_addr.s_addr,
  22687. X        (char *) hostentry->h_addr_list[naddr++],
  22688. X        hostentry->h_length);
  22689. X#else
  22690. X    memcpy ((char *) &sin.sin_addr.s_addr,
  22691. X        (char *) hostentry->h_addr,
  22692. X        hostentry->h_length);
  22693. X#endif
  22694. X    sin.sin_family = AF_INET;
  22695. X    sin.sin_port = htons (port);
  22696. X    memset (sin.sin_zero, EOS, sizeof (sin.sin_zero));
  22697. X    if (connect (sock_fd, (struct sockaddr *) &sin,
  22698. X         sizeof (struct sockaddr_in)) < 0) {
  22699. X      if (errno != EINPROGRESS) {
  22700. X#ifdef h_addr
  22701. X    if (!hostentry->h_addr_list[naddr]) {
  22702. X#endif
  22703. X      close (sock_fd);
  22704. X      return -1;
  22705. X#ifdef h_addr
  22706. X    }
  22707. X    else {
  22708. X      close (sock_fd);
  22709. X      continue;
  22710. X    }
  22711. X#endif
  22712. X      }
  22713. X      FD_ZERO (&readfds);
  22714. X      FD_ZERO (&writefds);
  22715. X      do {
  22716. X    FD_SET (sock_fd, &readfds);
  22717. X    FD_SET (sock_fd, &writefds);
  22718. X    errno = 0;
  22719. X    value = select ((nfds > 0 ? nfds : 20), &readfds, &writefds, NULL,
  22720. X            &timeout);
  22721. X      } while (value == -1 && errno == EINTR);
  22722. X
  22723. X      if (value < 0) {
  22724. X    close (sock_fd);
  22725. X    return -1;
  22726. X      }
  22727. X      break;    /* Successful connection */
  22728. X    }
  22729. X    else
  22730. X      break;
  22731. X  } while (007);
  22732. X# ifdef NONBLOCKING_IO
  22733. X  if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | O_NDELAY)) < 0) {
  22734. X    report_progress (report, "\nconnect_to_ilp_server(): Could not set \
  22735. Xnon-blocking I/O", TRUE);
  22736. X    close (sock_fd);
  22737. X    return -1;
  22738. X  }
  22739. X# endif
  22740. X# ifdef HAVE_SETJMP_H
  22741. X#  if defined (sco) || defined (M_XENIX) || defined (M_UNIX)
  22742. X  if (ioctl (sock_fd, I_SETSIG, S_INPUT) < 0) {
  22743. X    report_progress (report, "\nconnect_to_ilp_server(): Cannot set SIGIO",
  22744. X             TRUE);
  22745. X    close (sock_fd);
  22746. X    return -1;
  22747. X  }
  22748. X#  else
  22749. X#   ifdef F_SETOWN
  22750. X  if (fcntl (sock_fd, F_SETOWN, getpid()) < 0) {
  22751. X    report_progress (report, "\nconnect_to_ilp_server(): Cannot assign \
  22752. Xsocket to process group", TRUE);
  22753. X    close (sock_fd);
  22754. X    return -1;
  22755. X  }
  22756. X#   elif defined (SIOCSPGRP)
  22757. X  value = -getpid();
  22758. X  if (ioctl (sock_fd, SIOCSPGRP, (char *) &value) < 0) {
  22759. X    report_progress (report, "\nconnect_to_ilp_server(): Cannot assign \
  22760. Xsocket to process group", TRUE);
  22761. X    close (sock_fd);
  22762. X    return -1;
  22763. X  }
  22764. X#   else
  22765. X  report_progress (report, "\nconnect_to_ilp_server(): Cannot assign \
  22766. Xsocket to process group", TRUE);
  22767. X  close (sock_fd);
  22768. X  return -1;
  22769. X#   endif
  22770. X#   ifdef FASYNC
  22771. X  if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | FASYNC)) < 0) {
  22772. X    report_progress (report, "\nconnect_to_ilp_server(): Cannot set \
  22773. Xasynchronous I/O for socket", TRUE);
  22774. X    close (sock_fd);
  22775. X    return -1;
  22776. X  }
  22777. X#   elif defined (FIOASYNC)
  22778. X  value = 1;
  22779. X  if (ioctl (sock_fd, FIOASYNC, (char *) &value) < 0) {
  22780. X    report_progress (report, "\nconnect_to_ilp_server(): Cannot set \
  22781. Xasynchronous I/O for socket", TRUE);
  22782. X    close (sock_fd);
  22783. X    return -1;
  22784. X  }
  22785. X#   else
  22786. X  report_progress (report, "\nconnect_to_ilp_server(): Cannot set \
  22787. Xasynchronous I/O for socket", TRUE);
  22788. X  close (sock_fd);
  22789. X  return -1;
  22790. X#   endif
  22791. X#  endif
  22792. X# endif
  22793. X  return sock_fd;
  22794. X}
  22795. X
  22796. X# ifdef HAVE_SETJMP_H
  22797. X/*
  22798. X  Handle signals; the client sends an '__abort__' command and returns (long
  22799. X  jump); '__abort__' causes the other end to shut down.
  22800. X*/
  22801. X
  22802. Xint sighandle (int sig)
  22803. X{
  22804. X  check_sio = 0;
  22805. X  write (sock_fd, "__abort__\n", 10);
  22806. X  longjmp (env, 1);
  22807. X}
  22808. X
  22809. X/*
  22810. X  Urgent data from server; read it and return. Urgent data is received
  22811. X  when a connection is timed out or when the server shuts down.
  22812. X*/
  22813. X
  22814. Xint urg_data (int sig)
  22815. X{
  22816. X  int cmd;
  22817. X
  22818. X  if (!check_sio) {
  22819. X    signal (sig, (void (*)()) urg_data);
  22820. X    return 0;
  22821. X  }
  22822. X  signal (sig, SIG_IGN);
  22823. X  if ((cmd = ilp_server_response (sock_fd, 30)) >= 0)
  22824. X    if (cmd == CONN_ABORTED || cmd == CONN_TIMEOUT || cmd == CONN_CLOSED)
  22825. X      check_server_response (cmd, args, 30),
  22826. X      append_output = 1,
  22827. X      read_from_fd (sock_fd, nbytes, 30, ofd);
  22828. X  longjmp (env, 1);
  22829. X}
  22830. X# endif
  22831. X
  22832. X/*
  22833. X  Alarm signals a server timeout.
  22834. X*/
  22835. X
  22836. Xint alarm_clock (int sig)
  22837. X{
  22838. X  timed_out = 1;
  22839. X  signal (sig, (void (*)()) alarm_clock);
  22840. X}
  22841. X
  22842. X/*
  22843. X  Read from a socket and write to ofd.
  22844. X
  22845. X  Returns: the actual number of bytes read on succes, or the negative of
  22846. X  that number (or -1) on error.
  22847. X*/
  22848. X
  22849. Xlong int read_from_fd (int rfd, long int bytes_to_read, int response_timeout,
  22850. X               int ofd)
  22851. X{
  22852. X  long int bytes_read, total_bytes = 0;
  22853. X  char buf [BUFFSIZ];
  22854. X
  22855. X  timed_out = 0;
  22856. X  signal (SIGALRM, (void (*)()) alarm_clock);
  22857. X  alarm (response_timeout);
  22858. X  if (bytes_to_read <= 0)
  22859. X    return 0;
  22860. X  errno = 0;
  22861. X  while ((bytes_read = read (rfd, buf, MIN (bytes_to_read, BUFFSIZ))) <
  22862. X     bytes_to_read) {
  22863. X    if (bytes_read < 0 && errno && errno != EWOULDBLOCK && errno != EAGAIN &&
  22864. X    errno != EINTR
  22865. X#ifdef ERESTART
  22866. X    && errno != ERESTART
  22867. X#endif
  22868. X    ) {
  22869. X      char error [256];
  22870. X      sprintf (error, "\nread_from_fd(): ");
  22871. X      switch (errno) {
  22872. X    case EBADF: strcat (error, "Bad file number"); break;
  22873. X    case EFAULT: strcat (error, "Bad address"); break;
  22874. X    case EFBIG: strcat (error, "File limit reached"); break;
  22875. X    case EINVAL: strcat (error, "Negative seek pointer"); break;
  22876. X    case EIO: strcat (error, "I/O error"); break;
  22877. X    case ENOSPC: strcat (error, "No space left on device"); break;
  22878. X    case ENXIO: strcat (error, "No such device or address"); break;
  22879. X    case ERANGE: sprintf (error + strlen (error), "Bytes to read (%ld) \
  22880. Xout of range", bytes_to_read); break;
  22881. X#ifdef ENETRESET
  22882. X    case ENETRESET: strcat (error, "Network dropped connection"); break;
  22883. X#endif
  22884. X    default: sprintf (error + strlen (error), "Error number %d", errno);
  22885. X      }
  22886. X      report_progress (report, error, TRUE);
  22887. X      return (total_bytes > 0 ? -total_bytes : -1);
  22888. X    }
  22889. X    else if (timed_out)
  22890. X      return (total_bytes > 0 ? -total_bytes : -1);
  22891. X    if (bytes_read > 0) {
  22892. X      total_bytes += bytes_read;
  22893. X      bytes_to_read -= bytes_read;
  22894. X      if (to_file) {
  22895. X    if (bytes_to_read < prompt_len)
  22896. X      to_file = 0;
  22897. X    if (ofd && write_to_fd (ofd, buf,
  22898. X                (bytes_to_read < prompt_len ? 
  22899. X                 bytes_read - prompt_len + bytes_to_read :
  22900. X                 bytes_read)) < 0)
  22901. X      return (total_bytes > 0 ? -total_bytes : -1);
  22902. X      }
  22903. X      else if (append_output)
  22904. X    if (ofd, write_to_fd (ofd, buf,
  22905. X                  (bytes_to_read < prompt_len ? 
  22906. X                   bytes_read - prompt_len + bytes_to_read :
  22907. X                   bytes_read)) < 0)
  22908. X      return (total_bytes > 0 ? -total_bytes : -1);
  22909. X    }
  22910. X    errno = 0;
  22911. X  }
  22912. X  if (bytes_read > 0) {
  22913. X    total_bytes += bytes_read;
  22914. X    if ((append_output || to_file) && bytes_read > prompt_len)
  22915. X      if (ofd && write_to_fd (ofd, buf, bytes_read - prompt_len) < 0)
  22916. X    return -1;
  22917. X  }
  22918. X  to_file = 0;
  22919. X  signal (SIGALRM, SIG_IGN);
  22920. X  return total_bytes;
  22921. X}
  22922. X
  22923. X/*
  22924. X  Open a file for writing or appending. If 'test' is set, make sure
  22925. X  the file is writeable, notify the server and close the file; else prepare
  22926. X  for the transfer. When the server is inquiring about a file's write
  22927. X  permissions it sends zero bytes as the length of the message.
  22928. X
  22929. X  Returns: 0 on succes, -1 otherwise.
  22930. X*/
  22931. X
  22932. Xint open_file (char *file, int mode, int test)
  22933. X{
  22934. X  char msg [MAX_LINE];
  22935. X  int fd;
  22936. X
  22937. X  if ((fd = open (file, O_CREAT | mode, 0600)) < 0)
  22938. X    to_file = 0,
  22939. X    sprintf (msg, "%s: Permission denied.\n", file),
  22940. X    write_to_fd (ofd, msg, strlen (msg)),
  22941. X    nbytes = prompt_len,
  22942. X    sprintf (msg, "%d", PERMISSION_DENIED);
  22943. X  else {
  22944. X    if (nbytes > 0)
  22945. X      to_file = 1;
  22946. X    else
  22947. X      sprintf (msg, "%d", OK);
  22948. X    close (fd);
  22949. X  }
  22950. X  if (test)
  22951. X    if (write_to_fd (sock_fd, msg, strlen (msg)) < 0)
  22952. X      return -1;
  22953. X  return 0;
  22954. X}
  22955. X
  22956. X/*
  22957. X  Identify the server's response and take appropriate action.
  22958. X
  22959. X  Returns: 0 on success, -1 otherwise.
  22960. X*/
  22961. X
  22962. Xint check_server_response (int cmd, char *file, int response_timeout)
  22963. X{
  22964. X    switch (cmd) {
  22965. X    case OK:
  22966. X    case CONNECT:
  22967. X    case SYNTAX_ERROR:
  22968. X    case INVALID_REQ:
  22969. X    case BAD_ARCHIVE:
  22970. X    case RESTRICTED_REQ:
  22971. X    case NOT_OWNER:
  22972. X    case SYS_ERROR:
  22973. X    case SERVER_BUSY:
  22974. X    case PERMISSION_DENIED:
  22975. X    case CONN_CLOSED:
  22976. X    case PEER_UNAVAIL:
  22977. X    case MORE_INPUT_REQUIRED:
  22978. X    case MESSAGE:
  22979. X    case CONTINUED: break;
  22980. X    case PASSWORD_REQUIRED:
  22981. X     if (read_from_fd (sock_fd, nbytes, response_timeout, ofd) < 0)
  22982. X       return -1;
  22983. X     break;
  22984. X    case CONN_ABORTED:
  22985. X    case CONN_TIMEOUT: return -1; break;
  22986. X    case TEST_FILE_PERMISSIONS:
  22987. X     if (open_file (file, O_WRONLY | O_APPEND, 1)) return -1;
  22988. X     break;
  22989. X    case WRITE_TO_FILE_ASC:
  22990. X     if (open_file (file, O_WRONLY | O_TRUNC, 0)) return -1;
  22991. X     break;
  22992. X    case WRITE_TO_FILE_BIN:
  22993. X     if (open_file (file, O_WRONLY | O_TRUNC, 0)) return -1;
  22994. X     break;
  22995. X    case APPEND_TO_FILE_ASC:
  22996. X     if (open_file (file, O_WRONLY | O_APPEND, 0)) return -1;
  22997. X     break;
  22998. X    case APPEND_TO_FILE_BIN:
  22999. X     if (open_file (file, O_WRONLY | O_APPEND, 0)) return -1;
  23000. X     break;
  23001. X    default: write_to_fd (ofd, "Protocol error.\n", 16); return -1;
  23002. X  }
  23003. X  return 0;
  23004. X}
  23005. X
  23006. X/*
  23007. X  Check for input redirection, and if so check for for permissions too.
  23008. X
  23009. X  Returns: the opened file descriptor on succes, -1 on error.
  23010. X*/
  23011. X
  23012. Xint check_for_redirection (char *buf, char *infile)
  23013. X{
  23014. X  char *redirect, *s;
  23015. X  int fd = 0;
  23016. X
  23017. X  if ((redirect = strrchr (buf, '<')) != NULL)
  23018. X    if (redirect != buf && *(redirect - 1) == '\\')
  23019. X      sprintf (redirect - 1, "%s", redirect); /* Remove \ */
  23020. X    else {
  23021. X      RESET (infile);
  23022. X      sscanf (redirect + 1, "%s", infile);
  23023. X      if (infile [0] == EOS) {
  23024. X    write_to_fd (ofd, "Invalid null input redirect.\n", 29);
  23025. X    return -1;
  23026. X      }
  23027. X      if ((fd = open (infile, O_RDONLY)) < 0) {
  23028. X    write_to_fd (ofd, "File not found or inadequate permissions.\n", 42);
  23029. X    return -1;
  23030. X      }
  23031. X      s = redirect + 1; /* Remove < and file name */
  23032. X      while (*s == ' ' || *s == '\t') ++s;
  23033. X      while (*s != ' ' && *s != '\t' && *s != '\n') ++s;
  23034. X      sprintf (redirect, "%s", s);
  23035. X    }
  23036. X  return fd;
  23037. X}
  23038. X#endif
  23039. *-*-END-of-src/silp.c-*-*
  23040. echo x - src/start.c
  23041. sed 's/^X//' >src/start.c <<'*-*-END-of-src/start.c-*-*'
  23042. X/*
  23043. X  ----------------------------------------------------------------------------
  23044. X  |                     LISTPROCESSOR SYSTEM HOUSEKEEPER                     |
  23045. X  |                                                                          |
  23046. X  |                              Version 2.8                                 |
  23047. X  |                                                                          |
  23048. X  |                (or, when Computer Science gets to you)                   |
  23049. X  |                                                                          |
  23050. X  |                    Written by Anastasios Kotsikonas                      |
  23051. X  |                           (tasos@cs.bu.edu)                              |
  23052. X  |                                                                          |
  23053. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  23054. X  | whole and not in parts, as long as you do not remove or alter the author |
  23055. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  23056. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  23057. X  | provided for your personal use, you may not alter the functions          |
  23058. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  23059. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  23060. X  | any changes you may have made. No part of the source code bearing a         |
  23061. X  | copyright notice can be included in commercial software systems without  |
  23062. X  | written permission by the author.                         |
  23063. X  | By using this software you are bound by this agreement.                  |
  23064. X  | This software comes with no warranties and cannot be sold for profit.    |
  23065. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  23066. X  | files when distributing this software.                                   |
  23067. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas             |
  23068. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  23069. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  23070. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  23071. X  | (ii).                                                                    |
  23072. X  ----------------------------------------------------------------------------
  23073. X
  23074. X  This is the proper way of starting the system. The program verifies
  23075. X  that no other serverd, queued, list or listproc programs are running on the 
  23076. X  system (and kills them before proceeding -- after confirming), 
  23077. X  makes sure the required files exist (and creates new ones if missing -- 
  23078. X  after confirming), backs up all reports into files with extension .acc,
  23079. X  creates new directories for new mailing lists as necessary,
  23080. X  and finally spawns serverd. start reports to REPORT_START.
  23081. X
  23082. X  COMMAND LINE OPTIONS:
  23083. X    -k: just kill all pertinent programs that may already be running; no
  23084. X    mailing list is started in this case.
  23085. X    -c: Do not confirm before killing a process.
  23086. X    -r: Do not report; useful when starting up when system is rebooted.
  23087. X    -s: After a process is killed, start sleeps for some time. This turns
  23088. X    sleeping off -- to be used only when restarting the system via
  23089. X    a 'restart' request.
  23090. X  
  23091. X  WARNING: The program won't work correctly in the absence of an extended
  23092. X  egrep facility that does matching at the end of a line with a $ and 
  23093. X  accepts multiple regular expressions separated by a |. In this case,
  23094. X  the user may have to manually look for and terminate any such programs.
  23095. X  Also when the output of the 'ps' command exceeds 80 characters (due perhaps
  23096. X  to long path names) the user may again have to terminate programs by hand.
  23097. X  Note that a file locking mechanism  for serverd, list and listproc is used 
  23098. X  to ensure against multiple executions of the same program.
  23099. X
  23100. X  WARNING: When using the SYSV ps command and it chops output to 80 characters,
  23101. X  start may not be able to locate processes already running; this may occur if
  23102. X  the path to HOMEDIR is too long.
  23103. X*/
  23104. X
  23105. X#include <stdio.h>
  23106. X#include <sys/types.h>
  23107. X#include <string.h>
  23108. X#ifdef SYSLOG
  23109. X# ifdef ultrix
  23110. X#  include <sys/syslog.h>
  23111. X# else
  23112. X#  include <syslog.h>
  23113. X# endif
  23114. X#endif
  23115. X#include <signal.h>
  23116. X#if !defined (__convex__) && !defined (__NeXT__) && !defined (apollo) \
  23117. X && !defined (sequent) && !defined (unknown_port)
  23118. X# include <malloc.h>
  23119. X#endif
  23120. X#ifndef unknown_port
  23121. X# ifndef __NeXT__
  23122. X#  include <unistd.h>
  23123. X# else
  23124. X#  include <libc.h>
  23125. X# endif
  23126. X#endif
  23127. X#include <sys/stat.h>
  23128. X#include "defs.h"
  23129. X#include "start.h"
  23130. X#include "struct.h"
  23131. X#include "global.h"
  23132. X#if defined (__NeXT__) || defined (unknown_port)
  23133. X# include "next.h"
  23134. X#endif
  23135. X
  23136. X/*
  23137. X  Function prototypes:
  23138. X*/
  23139. X
  23140. X#ifdef __STDC__
  23141. X# include "ansi/misc.h"
  23142. X# include <stdarg.h>
  23143. Xextern int  syscom (char *, ...);
  23144. Xextern char *tsprintf (char *, ...);
  23145. X#else
  23146. X# include "nonansi/misc.h"
  23147. X# include <varargs.h>
  23148. Xextern int  syscom ();
  23149. Xextern char *tsprintf ();
  23150. X#endif
  23151. Xextern int  sys_config (FILE *, SYS *);
  23152. Xextern char *extract_filename (char *);
  23153. Xextern void report_progress (FILE *, char *, int);
  23154. Xextern int  _getopt (int, char **, char *);
  23155. Xextern void setup_string (char *, char *, char *);
  23156. Xextern void shrink (char *);
  23157. Xextern char *mystrdup (char *);
  23158. Xextern int echo (char *, char *);
  23159. Xextern int echo_append (char *, char *);
  23160. Xextern int mv (char *, char *);
  23161. Xextern int cp (char *, char *);
  23162. Xextern int cat (char *, char *);
  23163. Xextern int cat_append (char *, char *);
  23164. Xextern int touch (char *);
  23165. Xextern void init_signals (void);
  23166. Xextern void catch_signals (void);
  23167. Xextern int otoi (char *);
  23168. X
  23169. Xvoid   main (int, char **);
  23170. XBOOLEAN check_for (char *, FILE *, BOOLEAN, BOOLEAN);
  23171. Xvoid   check_unprocessed (char *, FILE *, BOOLEAN);
  23172. Xvoid   usage (void);
  23173. Xvoid   backup (char *, char *);
  23174. Xvoid   start_config (char *);
  23175. Xint    gexit (int);
  23176. Xchar   get_response (void);
  23177. X
  23178. Xvoid main (int argc, char **argv)
  23179. X{
  23180. X  char command [256];
  23181. X  char line [MAX_LINE];
  23182. X  char dir [MAX_LINE];
  23183. X  char *addr1, *addr2, *addr3, *addr4, *options = "ckrs";
  23184. X  int c;
  23185. X  FILE *f, *p;
  23186. X  int i, nlists, pid, procs_killed = 0, procs;
  23187. X  BOOLEAN just_kill = FALSE, confirm = TRUE, do_report = TRUE, sleepok = TRUE;
  23188. X  char *tmpps, *tmpfound, *tmpnprocs;
  23189. X  struct stat stat_buf;
  23190. X  extern char *getenv();
  23191. X  
  23192. X  while ((c = _getopt (argc, argv, options)) != EOF)
  23193. X    switch ((char) c) {
  23194. X      case 'c': confirm = FALSE; break;
  23195. X      case 'k': just_kill = TRUE; break;
  23196. X      case 'r': do_report = FALSE; break;
  23197. X      case 's': sleepok = FALSE; tty_echo = FALSE; break;
  23198. X      case '?':
  23199. X      default:
  23200. X    usage();
  23201. X    }
  23202. X
  23203. X  /* First make sure no other SERVERD programs are running. If so, kill
  23204. X     them all (after confirming) before proceeding. */
  23205. X  init_signals ();
  23206. X  catch_signals ();
  23207. X  signal (SIGINT, (void (*)()) gexit);
  23208. X  signal (SIGALRM, SIG_IGN);
  23209. X  if ((mask = getenv ("ULISTPROC_UMASK")))
  23210. X    umask (otoi (mask));
  23211. X  else
  23212. X    mask = "066",
  23213. X    umask (S_IRWXG|S_IRWXO); /* 600 */
  23214. X#ifdef SYSLOG
  23215. X  openlog ("ListProcessor: start", LOG_NDELAY
  23216. X# ifndef i386
  23217. X       |LOG_NOWAIT
  23218. X# endif
  23219. X       , SYSLOG);
  23220. X# ifndef ultrix
  23221. X  setlogmask (LOG_UPTO (LOG_INFO));
  23222. X# endif
  23223. X#else
  23224. X  backup (REPORT_START, REPORT_START_ACC);
  23225. X  if ((report = fopen (REPORT_START, "a")) == NULL)
  23226. X    fprintf (stderr, "start: Could not open %s\n", REPORT_START),
  23227. X    START_ABORT;
  23228. X  chmod (REPORT_START, 384); /* 600 */
  23229. X#endif
  23230. X  nlists = sys_config (report, &sys);
  23231. X  if (just_kill)
  23232. X    report_progress (report, "\n--- SHUTTING LISTPROCESSOR SYSTEM DOWN ---\n",
  23233. X             FALSE);
  23234. X  else
  23235. X    report_progress (report, "\n--- STARTING LISTPROCESSOR SYSTEM ---\n",
  23236. X             FALSE);
  23237. X#ifndef _MINIX
  23238. X  if (sys.options & BSD_PS)
  23239. X    syscom ("ps -gx > %s", (tmpps = mystrdup (tmpnam (NULL))));
  23240. X  else
  23241. X# ifdef __hp9000s800
  23242. X    syscom ("ps -ef | grep %s | sort > %s",
  23243. X# else
  23244. X    syscom ("ps -ef | grep %s > %s",
  23245. X# endif
  23246. X        ((addr1 = (char *) getenv ("LOGNAME")) == NULL ?
  23247. X          ((addr1 = (char *) getenv ("USER")) == NULL ? "server" : addr1) :
  23248. X          addr1), (tmpps = mystrdup (tmpnam (NULL))));
  23249. X  tty_echo = FALSE;
  23250. X  addr1 = extract_filename (LIST);
  23251. X  addr2 = extract_filename (SERVERD);
  23252. X  addr3 = extract_filename (SERVER);
  23253. X  addr4 = extract_filename (PQUEUE);
  23254. X  syscom ("egrep '%s |%s$|%s$|%s|%s$|%s |%s|%s |queued' %s > %s",
  23255. X      addr1, addr1, addr2, addr2, addr3, addr3, addr4, addr4, tmpps,
  23256. X      (tmpfound = mystrdup (tmpnam (NULL))));
  23257. X  free ((char *) addr1);
  23258. X  free ((char *) addr2);
  23259. X  free ((char *) addr3);
  23260. X  free ((char *) addr4);
  23261. X  unlink (tmpps);
  23262. X  free ((char *) tmpps);
  23263. X  if (sleepok)
  23264. X    tty_echo = TRUE;
  23265. X  if ((f = fopen (tmpfound, "r")) == NULL)
  23266. X    report_progress (report,
  23267. X             tsprintf ("Error opening %s. Aborting. %s", tmpfound,
  23268. X                   ((just_kill == FALSE) ?
  23269. X                "System not started." : "")), TRUE),
  23270. X    START_ABORT;
  23271. X  
  23272. X  syscom ("wc -l %s > %s", tmpfound, (tmpnprocs = mystrdup (tmpnam (NULL))));
  23273. X  if ((p = fopen (tmpnprocs, "r")) != NULL) {
  23274. X    fscanf (p, "%d", &procs);
  23275. X    if (do_report)
  23276. X      report_progress (report,
  23277. X               tsprintf ("OLD LISTPROCESSOR PROCESSES RUNNING: %d\n",
  23278. X                 procs), FALSE);
  23279. X    fclose (p);
  23280. X    unlink (tmpnprocs);
  23281. X    free ((char *) tmpnprocs);
  23282. X  }
  23283. X  else
  23284. X    report_progress (report,
  23285. X             tsprintf ("Error opening %s. Aborting. %s", tmpnprocs,
  23286. X                   ((just_kill == FALSE) ?
  23287. X                "System not started." : "")), TRUE),
  23288. X    START_ABORT;
  23289. X  
  23290. X  while (!feof (f)) {  /* get pid's and kill processes after confirming */
  23291. X    RESET (line);
  23292. X    fgets (line, MAX_LINE - 2, f);
  23293. X    if (line[0] != EOS) {
  23294. X      if (sys.options & BSD_PS)
  23295. X        sscanf (line, "%d ", &pid);
  23296. X      else
  23297. X#ifdef __hp9000s800
  23298. X    sscanf (line, "%*s %s %d ", command, &pid);
  23299. X#else
  23300. X        sscanf (line, "%s %d ", command, &pid);
  23301. X#endif
  23302. X      if (confirm) {
  23303. X# ifdef SIGSTOP
  23304. X    kill (pid, SIGSTOP);
  23305. X# elif defined (SIGSTP)
  23306. X    kill (pid, SIGSTP);
  23307. X# endif
  23308. X    c = EOS;
  23309. X        while (c != EOF && c != 'Y' && c != 'N' &&c != 'I') {
  23310. X# ifdef SYSLOG
  23311. X      printf ("\n%s\n%c[7m%s%c[mKill it to proceed ? (capital Y/N/Ignore) ",
  23312. X          ((just_kill == FALSE) ? 
  23313. X           "ERROR: another ListProcessor system program running:" : 
  23314. X           "ListProcessor system program found:"),
  23315. X          27, line, 27);
  23316. X# else
  23317. X      report_progress (report,
  23318. X               tsprintf ("\n%s\n%c[7m%s%c[mKill it to \
  23319. Xproceed ? (capital Y/N/Ignore) ",
  23320. X                     ((just_kill == FALSE) ? 
  23321. X                      "ERROR: another ListProcessor system program running:" : 
  23322. X                      "ListProcessor system program found:"),
  23323. X                     27, line, 27), FALSE);
  23324. X# endif
  23325. X      c = get_response ();
  23326. X        }
  23327. X# ifdef SIGCONT
  23328. X    kill (pid, SIGCONT);
  23329. X# elif defined (SIGCNT)
  23330. X    kill (pid, SIGCNT);
  23331. X# endif
  23332. X        if (c == 'N' || c == EOF)
  23333. X      report_progress (report, tsprintf ("start aborted. %s\n",
  23334. X                         ((just_kill == FALSE) ?
  23335. X                          "System not started.":"")), TRUE),
  23336. X      unlink (tmpfound),
  23337. X      exit (1);
  23338. X      }
  23339. X      if (c == 'Y' || !confirm)
  23340. X    kill (pid, SIGINT),
  23341. X    ++procs_killed;
  23342. X    }
  23343. X  }
  23344. X  fclose (f);
  23345. X  unlink (tmpfound);
  23346. X  free ((char *) tmpfound);
  23347. X  if (sleepok)
  23348. X    sleep (2);
  23349. X  for (i = 0; pids[i]; i++)
  23350. X    if ((f = fopen (pids[i], "r")) != NULL) {
  23351. X      fscanf (f, "%d", &pid);
  23352. X      if (pid)
  23353. X    kill (pid, SIGINT),
  23354. X    ++procs_killed;
  23355. X      fclose (f);
  23356. X      unlink (pids[i]);
  23357. X    }
  23358. X  syscom (tsprintf ("if [ -f %s ]; then rm %s; fi", SERVER_PIDS, SERVER_PIDS));
  23359. X  syscom (tsprintf ("if [ -f %s ]; then rm %s; fi", TMP_LIVE_FILES,
  23360. X            TMP_LIVE_FILES));
  23361. X  syscom (tsprintf ("if [ -f %s ]; then rm %s; fi", REPLY_FILES, REPLY_FILES));
  23362. X  if (do_report)
  23363. X    report_progress (report, tsprintf ("OLD LISTPROCESSOR PROCESSES KILLED: \
  23364. X%d\n", procs_killed), FALSE);
  23365. X  
  23366. X  if (just_kill)  /* Done */
  23367. X    report_progress (report, "", -TRUE),
  23368. X# ifdef SYSLOG
  23369. X    closelog (),
  23370. X# else
  23371. X    fclose (report),
  23372. X# endif
  23373. X    exit (0);
  23374. X  if (sleepok)
  23375. X    sleep (2);
  23376. X#endif
  23377. X  
  23378. X  echo ("Serverd lock file", SERVERD_LOCK_FILE);
  23379. X  echo ("Pqueue lock file", PQUEUE_LOCK_FILE);
  23380. X
  23381. X  backup (REPORT_SERVER, REPORT_SERVER_ACC);
  23382. X  backup (REPORT_SERVERD, REPORT_SERVERD_ACC);
  23383. X  backup (REPORT_PQUEUE, REPORT_PQUEUE_ACC);
  23384. X  SETUP_IGNOREDF;
  23385. X  check_for (server_ignoredf, report, do_report, confirm);
  23386. X  check_for (OWNERSF, report, do_report, confirm);
  23387. X  check_for (ALIASESF, report, do_report, confirm);
  23388. X  shrink (REPORT_CATMAIL);
  23389. X  syscom ("chmod u+s %s", CATMAIL);
  23390. X  for (i = 0; i < nlists; ++i) {
  23391. X    start_config (sys.lists[i].alias);
  23392. X    SETUP_DIR;
  23393. X    if (stat (dir, &stat_buf)) {
  23394. X      if (mkdir (dir, /*448*/ 0777 & (0777 ^ otoi (mask))))
  23395. X    report_progress (report, tsprintf ("Could not create directory %s", dir),
  23396. X             TRUE),
  23397. X    START_ABORT;
  23398. X      if (do_report)
  23399. X        report_progress (report, tsprintf ("*** New list %s ***\n",
  23400. X                       sys.lists[i].alias), FALSE);
  23401. X      cp (server_ignoredf, dir);
  23402. X      syscom ("echo '^%s$' >> %s/%s", sys.lists[i].alias, dir, IGNORED);
  23403. X      echo_append (sys.lists[i].address, tsprintf ("%s/%s", dir, IGNORED));
  23404. X      syscom ("echo %s | sed 's/listproc/server/' | sed 's/listproc/server/' \
  23405. X>> %s/%s", sys.server.address, dir, IGNORED);
  23406. X      touch (infof);
  23407. X      touch (welcomef);
  23408. X      touch (list_mail_f);
  23409. X      chmod (list_mail_f, /*416*/ 0666 & (0666 ^ otoi (mask)));
  23410. X      touch (tsprintf ("%s/%s", dir, MODERATED_MAIL_FILE));
  23411. X      chmod (tsprintf ("%s/%s", dir, MODERATED_MAIL_FILE),
  23412. X         0666 & (0666 ^ otoi (mask)));
  23413. X    }
  23414. X    check_for (subscribersf, report, do_report, confirm);
  23415. X    if (!check_for (aliasesf, report, do_report, confirm))
  23416. X      echo_append (DEFAULT_ALIASES, aliasesf);
  23417. X    check_for (newsf, report, do_report, confirm);
  23418. X    check_for (peersf, report, do_report, confirm);
  23419. X    check_for (restrictedf, report, do_report, confirm);
  23420. X    check_unprocessed (sys.lists[i].alias, report, do_report);
  23421. X    backup (report_listf, report_list_accf);
  23422. X  }
  23423. X  syscom ("%s %s &", SERVERD, sys.serverd_cmdoptions);
  23424. X  report_progress (report, "", -TRUE);
  23425. X#ifdef SYSLOG
  23426. X  closelog ();
  23427. X#else
  23428. X  fclose (report);
  23429. X#endif
  23430. X  exit (0);
  23431. X}
  23432. X
  23433. X/*
  23434. X  Make sure that file 's' exists. Create a new one if necessary. Return
  23435. X  TRUE if file exists, FALSE otherwise.
  23436. X*/
  23437. X
  23438. XBOOLEAN check_for (char *s, FILE *report, BOOLEAN do_report, BOOLEAN confirm)
  23439. X{
  23440. X  int c = EOS;
  23441. X  struct stat stat_buf;
  23442. X
  23443. X  if (stat (s, &stat_buf)) { /* make sure we have file 's' */
  23444. X    if (confirm) {
  23445. X      while (c != EOF && c != 'Y' && c != 'N') {
  23446. X     if (do_report)
  23447. X#ifdef SYSLOG
  23448. X          printf ("No %s file found. Create a new one? (capital Y/N) ",s),
  23449. X#else
  23450. X      report_progress (report, tsprintf ("No %s file found. Create a new \
  23451. Xone? (capital Y/N) ",s), FALSE);
  23452. X#endif
  23453. X        c = get_response ();
  23454. X      }
  23455. X      if (c == 'N' || c == EOF)
  23456. X        START_ABORT;
  23457. X    }
  23458. X    touch (s);
  23459. X    return FALSE;
  23460. X  }
  23461. X  return TRUE;
  23462. X}
  23463. X
  23464. X/*
  23465. X  Check for incomplete delivery for a list during the last run. The files
  23466. X  .unprocessed.* in the list's directory signify undelivered mail for
  23467. X  a subset of the subscribers/newsgroups/peers. Prepend the last undelivered
  23468. X  messages to the mail file, so that they are distributed again to the remaining
  23469. X  subscribers/newsgroups/peers.
  23470. X*/
  23471. X
  23472. Xvoid check_unprocessed (char *list, FILE *report, BOOLEAN do_report)
  23473. X{
  23474. X  struct stat stat_buf;
  23475. X  char *tmpmail;
  23476. X
  23477. X  if (!stat (unprocessed_subscribersf, &stat_buf) ||
  23478. X      !stat (unprocessed_peersf, &stat_buf) ||
  23479. X      !stat (unprocessed_newsf, &stat_buf) ||
  23480. X      !stat (unprocessed_digestf, &stat_buf) ||
  23481. X      !stat (unprocessed_messages, &stat_buf)) { /* Last delivery incomplete */
  23482. X    if (do_report)
  23483. X      report_progress (report, tsprintf ("\nList %s did not complete last \
  23484. Xdelivery\n", list), FALSE);
  23485. X    if (stat (unprocessed_messages, &stat_buf) &&
  23486. X    stat (unprocessed_digestf, &stat_buf)) {
  23487. X    if (do_report)
  23488. X      report_progress (report, tsprintf ("Last set of mail messages for \
  23489. Xlist %s lost; cannot resume delivery\n", list), FALSE);
  23490. X        unlink (unprocessed_subscribersf);
  23491. X        unlink (unprocessed_peersf);
  23492. X        unlink (unprocessed_newsf);
  23493. X        return;
  23494. X      }
  23495. X      else if (do_report)
  23496. X        report_progress (report, "Mail will be delivered to the remaining \
  23497. Xsubscribers/newsgroups/peers shortly\n", FALSE);
  23498. X    /* Create empty .unprocessed files for subscribers/newsgroups/peers
  23499. X       that do not exist. */
  23500. X    touch (unprocessed_subscribersf);
  23501. X    touch (unprocessed_peersf);
  23502. X    touch (unprocessed_newsf);
  23503. X    /* Now prepend undelivered message(s) to the mail file */
  23504. X    mv (list_mail_f, (tmpmail = mystrdup (tmpnam (NULL))));
  23505. X    cat (unprocessed_messages, list_mail_f);
  23506. X    cat_append (tmpmail, list_mail_f);
  23507. X    unlink (tmpmail);
  23508. X    free ((char *) tmpmail);
  23509. X    unlink (unprocessed_messages);
  23510. X    chmod (list_mail_f, /*416*/ 0666 & (0666 ^ otoi (mask)));
  23511. X  }
  23512. X}
  23513. X
  23514. X/*
  23515. X  Append 'src' to 'dest' and create a brand new 'src'.
  23516. X*/
  23517. X
  23518. Xvoid backup (char *src, char *dest)
  23519. X{
  23520. X  struct stat stat_buf;
  23521. X
  23522. X  if (!stat (src, &stat_buf)) /* prepare for backup */
  23523. X    cat_append (src, dest),
  23524. X    chmod (dest, 384), /* 600 */
  23525. X    unlink (src),
  23526. X    touch (src),
  23527. X    chmod (src, 384);
  23528. X}
  23529. X
  23530. X/*
  23531. X  Print usage.
  23532. X*/
  23533. X
  23534. Xvoid usage ()
  23535. X{
  23536. X  fprintf (stderr, "Usage: start [-k] [-c] [-r]\n\
  23537. X-k: Just kill any ListProcessor system programs running.\n\
  23538. X-c: Do not confirm before killing processes.\n\
  23539. X-r: Restrict reporting to screen.\n");
  23540. X  exit (1);
  23541. X}
  23542. X
  23543. Xvoid start_config (char *alias)
  23544. X{
  23545. X  setup_string (subscribersf, alias, SUBSCRIBERS);
  23546. X  setup_string (aliasesf, alias, ALIASES);
  23547. X  setup_string (newsf, alias, NEWSF);
  23548. X  setup_string (peersf, alias, PEERS);
  23549. X  setup_string (restrictedf, alias, RESTRICTED);
  23550. X  setup_string (ignoredf, alias, IGNORED);
  23551. X  setup_string (report_listf, alias, REPORT_LIST);
  23552. X  setup_string (infof, alias, INFO_FILE);
  23553. X  setup_string (welcomef, alias, WELCOME_FILE);
  23554. X  setup_string (unprocessed_subscribersf, alias, UNPROC_SUBSCRIBERS);
  23555. X  setup_string (unprocessed_peersf, alias, UNPROC_PEERS);
  23556. X  setup_string (unprocessed_newsf, alias, UNPROC_NEWS);
  23557. X  setup_string (unprocessed_messages, alias, UNPROC_MESSAGES);
  23558. X  setup_string (unprocessed_digestf, alias, UNPROC_DIGEST);
  23559. X  setup_string (list_mail_f, alias, LIST_MAIL_FILE);
  23560. X  setup_string (report_list_accf, alias, REPORT_LIST_ACC);
  23561. X}
  23562. X
  23563. X/*
  23564. X  Required to avoid undefined symbols.
  23565. X*/
  23566. X
  23567. Xint gexit (int exitcode)
  23568. X{
  23569. X  exit (exitcode);
  23570. X}
  23571. X
  23572. X/*
  23573. X  Get a one-character response from stdin.
  23574. X*/
  23575. X
  23576. Xchar get_response ()
  23577. X{
  23578. X  char c;
  23579. X
  23580. X  fflush (stdout);
  23581. X  fflush (stdin);
  23582. X  c = fgetc (stdin);
  23583. X
  23584. X  if (c != '\n' && c != EOF)
  23585. X    while (fgetc (stdin) != '\n');
  23586. X  fflush (stdin);
  23587. X  return c;
  23588. X}
  23589. *-*-END-of-src/start.c-*-*
  23590. echo x - src/strftime.c
  23591. sed 's/^X//' >src/strftime.c <<'*-*-END-of-src/strftime.c-*-*'
  23592. X#ifndef lint
  23593. X#ifndef NOID
  23594. Xstatic char    elsieid[] = "@(#)strftime.c    7.1";
  23595. X/*
  23596. X** Based on the UCB version whose ID appears below.
  23597. X** This is ANSIish only when time is treated identically in all locales and
  23598. X** when "multibyte character == plain character".
  23599. X*/
  23600. X#endif /* !defined NOID */
  23601. X#endif /* !defined lint */
  23602. X/*
  23603. X * Copyright (c) 1989 The Regents of the University of California.
  23604. X * All rights reserved.
  23605. X *
  23606. X * Redistribution and use in source and binary forms are permitted
  23607. X * provided that the above copyright notice and this paragraph are
  23608. X * duplicated in all such forms and that any documentation,
  23609. X * advertising materials, and other materials related to such
  23610. X * distribution and use acknowledge that the software was developed
  23611. X * by the University of California, Berkeley.  The name of the
  23612. X * University may not be used to endorse or promote products derived
  23613. X * from this software without specific prior written permission.
  23614. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  23615. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23616. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  23617. X */
  23618. X
  23619. X#if defined(LIBC_SCCS) && !defined(lint)
  23620. Xstatic char sccsid[] = "@(#)strftime.c    5.4 (Berkeley) 3/14/89";
  23621. X#endif /* LIBC_SCCS and not lint */
  23622. X
  23623. X#include <sys/types.h>
  23624. X#include <time.h>
  23625. X#ifdef HAVE_TZFILE_H
  23626. X# include <tzfile.h>
  23627. X#else
  23628. X# define TM_YEAR_BASE    1900
  23629. X#endif
  23630. X
  23631. Xstatic char *afmt[] = {
  23632. X    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
  23633. X};
  23634. Xstatic char *Afmt[] = {
  23635. X    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
  23636. X    "Saturday",
  23637. X};
  23638. Xstatic char *bfmt[] = {
  23639. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
  23640. X    "Oct", "Nov", "Dec",
  23641. X};
  23642. Xstatic char *Bfmt[] = {
  23643. X    "January", "February", "March", "April", "May", "June", "July",
  23644. X    "August", "September", "October", "November", "December",
  23645. X};
  23646. X
  23647. Xstatic size_t gsize;
  23648. Xstatic char *pt;
  23649. X
  23650. Xstatic void _add();
  23651. Xstatic void _conv();
  23652. Xstatic void _fmt();
  23653. X
  23654. Xsize_t
  23655. Xucb_strftime(s, maxsize, format, t)
  23656. X    char *s;
  23657. X    char *format;
  23658. X    size_t maxsize;
  23659. X    struct tm *t;
  23660. X{
  23661. X    pt = s;
  23662. X    gsize = maxsize;
  23663. X    _fmt(format, t);
  23664. X    if (gsize <= 0)
  23665. X        return(0);
  23666. X    *pt = '\0';
  23667. X    return(maxsize - gsize);
  23668. X}
  23669. X
  23670. Xstatic void
  23671. X_fmt(format, t)
  23672. X    register char *format;
  23673. X    struct tm *t;
  23674. X{
  23675. X    for (; *format; ++format) {
  23676. X        if (*format == '%')
  23677. X            switch(*++format) {
  23678. X            case '\0':
  23679. X                --format;
  23680. X                break;
  23681. X            case 'A':
  23682. X                if (t->tm_wday < 0 || t->tm_wday > 6)
  23683. X                    _add("?");
  23684. X                else    _add(Afmt[t->tm_wday]);
  23685. X                continue;
  23686. X            case 'a':
  23687. X                if (t->tm_wday < 0 || t->tm_wday > 6)
  23688. X                    _add("?");
  23689. X                else    _add(afmt[t->tm_wday]);
  23690. X                continue;
  23691. X            case 'B':
  23692. X                if (t->tm_mon < 0 || t->tm_mon > 11)
  23693. X                    _add("?");
  23694. X                else    _add(Bfmt[t->tm_mon]);
  23695. X                continue;
  23696. X            case 'b':
  23697. X            case 'h':
  23698. X                if (t->tm_mon < 0 || t->tm_mon > 11)
  23699. X                    _add("?");
  23700. X                else    _add(bfmt[t->tm_mon]);
  23701. X                continue;
  23702. X            case 'c':
  23703. X                _fmt("%D %X", t);
  23704. X                continue;
  23705. X            case 'C':
  23706. X                _fmt("%a %b %e %X %Y", t);
  23707. X                continue;
  23708. X            case 'D':
  23709. X            case 'x':
  23710. X                _fmt("%m/%d/%y", t);
  23711. X                continue;
  23712. X            case 'd':
  23713. X                _conv(t->tm_mday, 2, '0');
  23714. X                continue;
  23715. X            case 'e':
  23716. X                _conv(t->tm_mday, 2, ' ');
  23717. X                continue;
  23718. X            case 'H':
  23719. X                _conv(t->tm_hour, 2, '0');
  23720. X                continue;
  23721. X            case 'I':
  23722. X                _conv(t->tm_hour % 12 ?
  23723. X                    t->tm_hour % 12 : 12, 2, '0');
  23724. X                continue;
  23725. X            case 'j':
  23726. X                _conv(t->tm_yday + 1, 3, '0');
  23727. X                continue;
  23728. X            case 'k':
  23729. X                _conv(t->tm_hour % 12 ?
  23730. X                    t->tm_hour % 12 : 12, 2, ' ');
  23731. X                continue;
  23732. X#ifdef KITCHEN_SINK
  23733. X            case 'K':
  23734. X                _add("kitchen sink");
  23735. X                continue;
  23736. X#endif /* defined KITCHEN_SINK */
  23737. X            case 'l':
  23738. X                _conv(t->tm_hour, 2, ' ');
  23739. X                continue;
  23740. X            case 'M':
  23741. X                _conv(t->tm_min, 2, '0');
  23742. X                continue;
  23743. X            case 'm':
  23744. X                _conv(t->tm_mon + 1, 2, '0');
  23745. X                continue;
  23746. X            case 'n':
  23747. X                _add("\n");
  23748. X                continue;
  23749. X            case 'p':
  23750. X                _add(t->tm_hour >= 12 ? "PM" : "AM");
  23751. X                continue;
  23752. X            case 'R':
  23753. X                _fmt("%H:%M", t);
  23754. X                continue;
  23755. X            case 'r':
  23756. X                _fmt("%I:%M:%S %p", t);
  23757. X                continue;
  23758. X            case 'S':
  23759. X                _conv(t->tm_sec, 2, '0');
  23760. X                continue;
  23761. X            case 'T':
  23762. X            case 'X':
  23763. X                _fmt("%H:%M:%S", t);
  23764. X                continue;
  23765. X            case 't':
  23766. X                _add("\t");
  23767. X                continue;
  23768. X            case 'U':
  23769. X                _conv((t->tm_yday + 7 - t->tm_wday) / 7,
  23770. X                    2, '0');
  23771. X                continue;
  23772. X            case 'W':
  23773. X                _conv((t->tm_yday + 7 -
  23774. X                    (t->tm_wday ? (t->tm_wday - 1) : 6))
  23775. X                    / 7, 2, '0');
  23776. X                continue;
  23777. X            case 'w':
  23778. X                _conv(t->tm_wday, 1, '0');
  23779. X                continue;
  23780. X            case 'y':
  23781. X                _conv((t->tm_year + TM_YEAR_BASE) % 100,
  23782. X                    2, '0');
  23783. X                continue;
  23784. X            case 'Y':
  23785. X                _conv(t->tm_year + TM_YEAR_BASE, 4, '0');
  23786. X                continue;
  23787. X            case 'Z':
  23788. X#ifdef TM_ZONE
  23789. X                if (t->TM_ZONE)
  23790. X                    _add(t->TM_ZONE);
  23791. X                else
  23792. X#endif /* defined TM_ZONE */
  23793. X                if (t->tm_isdst == 0 || t->tm_isdst == 1) {
  23794. X                    extern char *    tzname[2];
  23795. X
  23796. X                    _add(tzname[t->tm_isdst]);
  23797. X                } else    _add("?");
  23798. X                continue;
  23799. X            case '%':
  23800. X            /*
  23801. X             * X311J/88-090 (4.12.3.5): if conversion char is
  23802. X             * undefined, behavior is undefined.  Print out the
  23803. X             * character itself as printf(3) also does.
  23804. X             */
  23805. X            default:
  23806. X                break;
  23807. X        }
  23808. X        if (gsize <= 0)
  23809. X            return;
  23810. X        *pt++ = *format;
  23811. X        --gsize;
  23812. X    }
  23813. X}
  23814. X
  23815. Xstatic void
  23816. X_conv(n, digits, fill)
  23817. X    int n, digits, fill;
  23818. X{
  23819. X    static char buf[10];
  23820. X    register char *p;
  23821. X
  23822. X    for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
  23823. X        *p-- = n % 10 + '0';
  23824. X    while (p > buf && digits-- > 0)
  23825. X        *p-- = fill;
  23826. X    _add(++p);
  23827. X}
  23828. X
  23829. Xstatic void
  23830. X_add(str)
  23831. X    register char *str;
  23832. X{
  23833. X    for (;; ++pt, --gsize) {
  23834. X        if (gsize <= 0)
  23835. X            return;
  23836. X        if (!(*pt = *str++))
  23837. X            return;
  23838. X    }
  23839. X}
  23840. X
  23841. *-*-END-of-src/strftime.c-*-*
  23842. echo x - src/sysmail.c
  23843. sed 's/^X//' >src/sysmail.c <<'*-*-END-of-src/sysmail.c-*-*'
  23844. X/*
  23845. X  ----------------------------------------------------------------------------
  23846. X  |                       SYSTEM MAILING ROUTINES                            |
  23847. X  |                                         |
  23848. X  |                             Version 2.7                                  |
  23849. X  |                                                                          |
  23850. X  |                (or, when Computer Science gets to you)                   |
  23851. X  |                                                                          |
  23852. X  |                    Written by Anastasios Kotsikonas                      |
  23853. X  |                           (tasos@cs.bu.edu)                              |
  23854. X  |                                                                          |
  23855. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  23856. X  | whole and not in parts, as long as you do not remove or alter the author |
  23857. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  23858. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  23859. X  | provided for your personal use, you may not alter the functions          |
  23860. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  23861. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  23862. X  | any changes you may have made. No part of the source code bearing a         |
  23863. X  | copyright notice can be included in commercial software systems without  |
  23864. X  | written permission by the author.                         |
  23865. X  | By using this software you are bound by this agreement.                  |
  23866. X  | This software comes with no warranties and cannot be sold for profit.    |
  23867. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  23868. X  | files when distributing this software.                                   |
  23869. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  23870. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  23871. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  23872. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  23873. X  | (ii).                                                                    |
  23874. X  ----------------------------------------------------------------------------
  23875. X
  23876. X  These routines implement the 'system' mailmethod. The system opens a socket
  23877. X  and connects directly with sendmail for mail delivery. During the process
  23878. X  of porting the code to various platforms, lots of grosse things were
  23879. X  encountered with sockets and protocols, so the code may seem kludgy.
  23880. X
  23881. X  When mail cannot be sent due to network problems, it is queued up and will 
  23882. X  be delivered later by the queue daemon.
  23883. X*/
  23884. X
  23885. X#include <stdio.h>
  23886. X#include <string.h>
  23887. X#ifndef unknown_port
  23888. X# ifndef __NeXT__
  23889. X#  include <unistd.h>
  23890. X# else
  23891. X#  include <libc.h>
  23892. X# endif
  23893. X#endif
  23894. X#include <sys/types.h>
  23895. X#include <sys/stat.h>
  23896. X#include "defs.h"
  23897. X#include "struct.h"
  23898. X#include "sysmail.h"
  23899. X#ifdef TCP_IP
  23900. X# include <fcntl.h>
  23901. X# include <errno.h>
  23902. X# ifdef unknown_port
  23903. Xextern int errno;
  23904. X# endif
  23905. X# include <sys/socket.h>
  23906. X# include <netinet/in.h>
  23907. X# include <netdb.h>
  23908. X# if (defined (sco) || defined (M_XENIX) || defined (M_UNIX)) && \
  23909. X  defined (HAVE_SELECT_H)
  23910. X#  include <sys/times.h>
  23911. X# else
  23912. X#  include <sys/time.h>
  23913. X# endif
  23914. X# ifdef HAVE_SELECT_H
  23915. X#  include <sys/select.h>
  23916. X# endif
  23917. X# ifdef HAVE_ULIMIT_H
  23918. X#  include <ulimit.h>
  23919. X# endif
  23920. X# ifndef UL_GDESLIM
  23921. X#  define UL_GDESLIM      4
  23922. X# endif
  23923. X# ifndef FD_SET          /* for 4.2BSD */
  23924. X#  define FD_SETSIZE      (sizeof(fd_set) * 8)
  23925. X#  define FD_SET(n, p)    (((fd_set *) (p))->fds_bits[0] |= (1 << ((n) % 32)))
  23926. X#  define FD_CLR(n, p)    (((fd_set *) (p))->fds_bits[0] &= ~(1 << ((n) % 32)))
  23927. X#  define FD_ISSET(n, p)  (((fd_set *) (p))->fds_bits[0] & (1 << ((n) % 32)))
  23928. X#  define FD_ZERO(p)      memset ((char *)(p), '\0', sizeof(*(p)))
  23929. X# endif
  23930. X#endif
  23931. X
  23932. X#ifdef __STDC__
  23933. X# include <stdarg.h>
  23934. Xextern int  syscom (char *, ...);
  23935. Xextern char *tsprintf (char *, ...);
  23936. X#else
  23937. X# include <varargs.h>
  23938. Xextern int  syscom ();
  23939. Xextern char *tsprintf ();
  23940. X#endif
  23941. Xextern FILE *report;
  23942. Xextern SYS sys;
  23943. Xextern BOOLEAN debug;
  23944. Xextern int listid;
  23945. X
  23946. X#ifndef __NeXT__
  23947. Xextern long int atoi (char *);
  23948. X#else
  23949. Xextern int atoi (const char *);
  23950. X#endif
  23951. Xextern void report_progress (FILE *, char *, int);
  23952. Xextern int gexit (int);
  23953. Xextern int echo (char *, char *);
  23954. Xextern int mv (char *, char *);
  23955. X
  23956. XBOOLEAN sysmail (char *);
  23957. X#ifdef TCP_IP
  23958. XBOOLEAN _sysmail (char *, int);
  23959. Xint     server_response (int);
  23960. Xint     build_tcp_connection (FILE *);
  23961. Xvoid    queue_up (char *file);
  23962. X#endif
  23963. X
  23964. X/*
  23965. X  The return value depends on the return value of _sysmail ().
  23966. X*/
  23967. X
  23968. XBOOLEAN sysmail (char *file)
  23969. X{
  23970. X#ifdef TCP_IP
  23971. X  queue = FALSE;
  23972. X  if (debug) {
  23973. X    OPEN_FILE (sent, SENT, "w", "sysmail");
  23974. X    OPEN_FILE (received, RECEIVED_, "w", "sysmail");
  23975. X  }
  23976. X  return _sysmail (file, 1);
  23977. X#endif
  23978. X}
  23979. X#ifdef TCP_IP
  23980. X
  23981. X/*
  23982. X  'system' mailmethod. It returns TRUE if the mail was successfully
  23983. X  delivered, FALSE if it was queued.
  23984. X*/
  23985. X
  23986. XBOOLEAN _sysmail (char *file, int call)
  23987. X{
  23988. X  char buf [MAX_LINE] ;
  23989. X  FILE *msg;
  23990. X  int sock_fd, cmd, bytes_to_write, bytes_written, i;
  23991. X   
  23992. X  OPEN_FILE (msg, file, "r", "_sysmail");
  23993. X  if ((sock_fd = build_tcp_connection (report)) < 0) {
  23994. X    queue = TRUE;
  23995. X    goto abort;
  23996. X  }
  23997. X  if ((cmd = server_response (sock_fd)) != ACKNOWLEDGE) {
  23998. X    report_progress (report, "\n_sysmail(): Could not connect to sendmail",
  23999. X             TRUE);
  24000. X    queue = TRUE;
  24001. X    goto abort;
  24002. X  }
  24003. X
  24004. X  PROTOCOL (DATA);
  24005. X  while (!feof (msg) && strcmp (buf, END_OF_TEXT)) { /* Copy header and text */
  24006. X    RESET (buf);
  24007. X    fgets (buf, MAX_LINE - 2, msg);
  24008. X    WRITE_TO_SOCKET (sock_fd, buf);
  24009. X  }
  24010. X  cmd = server_response (sock_fd);
  24011. X  CHECK_SERVER_RESPONSE (cmd, OK, NULL);
  24012. X  PROTOCOL (CLOSE_CONNECTION);
  24013. X
  24014. X  abort:
  24015. X  if (queue)
  24016. X    queue_up (file);
  24017. X  CLOSEF;
  24018. X  if (debug)
  24019. X    fclose (sent),
  24020. X    fclose (received);
  24021. X  return !queue;
  24022. X}
  24023. X
  24024. X/*
  24025. X  Get server response. Return the command number that sendmail sent,
  24026. X  CONN_TIMEOUT or HOST_ABORTED.
  24027. X*/
  24028. X
  24029. Xint server_response (int sock_fd)
  24030. X{
  24031. X  char buf [MAX_LINE];
  24032. X  long int cmd, i, column = 3, bytes_to_read = 3, bytes_read = 0;
  24033. X  int nfds, value;
  24034. X  BOOLEAN done = FALSE, continued = FALSE;
  24035. X  fd_set rfds;
  24036. X  struct timeval timeout;
  24037. X
  24038. X# if defined (sequent) || defined (__NeXT__) || defined (__convex__) || \
  24039. X  defined (apollo) || defined (unknown_port)
  24040. X  nfds = getdtablesize ();
  24041. X# else
  24042. X  nfds = ulimit (UL_GDESLIM);
  24043. X# endif
  24044. X  RESET (buf);
  24045. X  while (bytes_to_read) {
  24046. X    /* Get server command */
  24047. X    FD_ZERO (&rfds);
  24048. X    do {
  24049. X      FD_SET (sock_fd, &rfds);
  24050. X      timeout.tv_sec  = timeout.tv_usec = TIMEOUT;
  24051. X      errno = 0;
  24052. X      value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
  24053. X    } while (value == -1 && errno == EINTR);
  24054. X
  24055. X    if (value == 0)
  24056. X      return CONN_TIMEOUT;
  24057. X    else if (value < 0) {
  24058. X      report_progress (report, tsprintf ("\nserver_response: select() failed;\
  24059. X errno %d\n", errno), TRUE);
  24060. X      return -1;    /* = CONN_TIMEOUT */
  24061. X    }
  24062. X
  24063. X    errno = 0;
  24064. X    if ((bytes_read = read (sock_fd, &buf [3 - bytes_to_read], bytes_to_read))
  24065. X    < 0)
  24066. X      if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
  24067. X      errno == ECONNREFUSED)
  24068. X    return HOST_ABORTED;
  24069. X    if (bytes_read > 0)
  24070. X      bytes_to_read -= bytes_read;
  24071. X  }
  24072. X  RESET (message);
  24073. X  buf[3] = EOS;
  24074. X  cmd = atoi (buf);
  24075. X  sprintf (message, "%s", buf);
  24076. X  i = strlen (message);
  24077. X  if (debug)
  24078. X    fprintf (received, "%s", buf),
  24079. X    fflush (received);
  24080. X  while (!done) { /* Read till the end of socket */
  24081. X    FD_ZERO (&rfds);
  24082. X    do {
  24083. X      FD_SET (sock_fd, &rfds);
  24084. X      timeout.tv_sec = timeout.tv_usec = TIMEOUT;
  24085. X      errno = 0;
  24086. X      value = select ((nfds > 0 ? nfds : 20), &rfds, NULL, NULL, &timeout);
  24087. X    } while (value == -1 && errno == EINTR);
  24088. X
  24089. X    if (value == 0)
  24090. X      return CONN_TIMEOUT;
  24091. X    else if (value < 0) {
  24092. X      report_progress (report, tsprintf ("\nserver_response: select() failed;\
  24093. X errno %d\n", errno), TRUE);
  24094. X      return -1;    /* = CONN_TIMEOUT */
  24095. X    }
  24096. X
  24097. X    errno = 0;
  24098. X    if ((bytes_read = read (sock_fd, buf, 1)) < 1)
  24099. X      if (errno == EBADF || errno == ECONNRESET || errno == ECONNABORTED ||
  24100. X      errno == ECONNREFUSED)
  24101. X    return HOST_ABORTED;
  24102. X    if (bytes_read > 0) {
  24103. X      ++column;
  24104. X      if (buf[0] == '\n') {
  24105. X    column = 0;
  24106. X    if (!continued)
  24107. X      done = TRUE;
  24108. X      }
  24109. X      if (column == 4)
  24110. X    if (buf[0] != '-')
  24111. X      continued = FALSE;
  24112. X    else
  24113. X      continued = TRUE;
  24114. X      message [i++] = buf[0];
  24115. X      if (debug)
  24116. X    fprintf (received, "%c", buf[0]),
  24117. X    fflush (received);
  24118. X    }
  24119. X  }
  24120. X  message [i] = EOS;
  24121. X  return cmd;
  24122. X}
  24123. X
  24124. X/*
  24125. X  Establish connection with sendmail/smtp.
  24126. X*/
  24127. X
  24128. Xint build_tcp_connection (FILE *report)
  24129. X{
  24130. X  int sock_fd;
  24131. X  struct sockaddr_in sin;
  24132. X  struct hostent *hostentry;
  24133. X   
  24134. X  if (! (hostentry = gethostbyname (SENDMAIL_HOST))) {
  24135. X    report_progress (report, "\nbuild_tcp_connection(): No such host", TRUE);
  24136. X    return -1;
  24137. X  }
  24138. X  if ((sock_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  24139. X    report_progress (report, "\nbuild_tcp_connection(): Could not create \
  24140. Xsocket", TRUE);
  24141. X    return -1;
  24142. X  }
  24143. X  sin.sin_family = AF_INET;
  24144. X  sin.sin_port = htons (PORT);
  24145. X  memcpy ((char *) &sin.sin_addr.s_addr, (char *) hostentry->h_addr,
  24146. X      hostentry->h_length);
  24147. X  memset (sin.sin_zero, EOS, sizeof (sin.sin_zero));
  24148. X  if (connect (sock_fd, (struct sockaddr *) &sin, sizeof (struct sockaddr_in))
  24149. X      < 0) {
  24150. X    report_progress (report, "\nbuild_tcp_connection(): Could not connect to \
  24151. Xport", TRUE);
  24152. X    close (sock_fd);
  24153. X    return -1;
  24154. X  }
  24155. X# ifdef NONBLOCKING_IO
  24156. X  if (fcntl (sock_fd, F_SETFL, (fcntl (sock_fd, F_GETFL, 0) | O_NDELAY)) < 0)
  24157. X    report_progress (report, "\nbuild_tcp_connection(): WARNING: timeout \
  24158. Xmechanism not functional", TRUE);
  24159. X# endif
  24160. X  return sock_fd;
  24161. X}
  24162. X
  24163. X/*
  24164. X  Queue up a file for later delivery.
  24165. X*/
  24166. X
  24167. Xvoid queue_up (char *file)
  24168. X{
  24169. X  FILE *id;
  24170. X  int id_no = 0;
  24171. X  char msg [MAX_LINE];
  24172. X
  24173. X  if ((id = fopen (IDF, "r")) != NULL)
  24174. X    fscanf (id, "%d\n", &id_no),
  24175. X    fclose (id);
  24176. X  mv (file, tsprintf ("%s/%d", QUEUE_DIR, ++id_no));
  24177. X  echo (tsprintf ("%d", id_no), IDF);
  24178. X  sprintf (msg, "File %s placed in the mail queue", file);
  24179. X  report_progress (report, msg, TRUE);
  24180. X}
  24181. X#endif
  24182. *-*-END-of-src/sysmail.c-*-*
  24183. echo x - src/tlock.c
  24184. sed 's/^X//' >src/tlock.c <<'*-*-END-of-src/tlock.c-*-*'
  24185. X/*
  24186. X  ----------------------------------------------------------------------------
  24187. X  |                        tlock UTILITY                      |
  24188. X  |                                                                          |
  24189. X  |                              Version 2.1                                 |
  24190. X  |                                                                          |
  24191. X  |                (or, when Computer Science gets to you)                   |
  24192. X  |                                                                          |
  24193. X  |                    Written by Anastasios Kotsikonas                      |
  24194. X  |                           (tasos@cs.bu.edu)                              |
  24195. X  |                                                                          |
  24196. X  | AGREEMENT: This software can be used and distributed freely only as a    |
  24197. X  | whole and not in parts, as long as you do not remove or alter the author |
  24198. X  | and copyright notices in the file defs.h; this notices are #define'd in  |
  24199. X  | the symbols VERSION and COPYRIGHT. Although you may alter the code         |
  24200. X  | provided for your personal use, you may not alter the functions          |
  24201. X  | create_header(), create_multi_recipient_header() and main() in list.c,   |
  24202. X  | listproc.c and serverd.c (where applicable), and you may not redistribute|
  24203. X  | any changes you may have made. No part of the source code bearing a         |
  24204. X  | copyright notice can be included in commercial software systems without  |
  24205. X  | written permission by the author.                         |
  24206. X  | By using this software you are bound by this agreement.                  |
  24207. X  | This software comes with no warranties and cannot be sold for profit.    |
  24208. X  | The AGREEMENT and COPYRIGHT notices should be included in all source     |
  24209. X  | files when distributing this software.                                   |
  24210. X  | COPYRIGHT: Copyright (c) 1991-93, Anastasios C. Kotsikonas               |
  24211. X  | Use, duplication or disclosure by the Federal Government is subject to   |
  24212. X  | the restrictions set forth in FAR 52.227-19(c), Commercial Computer      |
  24213. X  | Software or, for Department of Defense Users, by DFAR 252.227-7013(c)(1) |
  24214. X  | (ii).                                                                    |
  24215. X  |                                         |
  24216. X  | Enhanced by: Warren Burstein.                         |
  24217. X  ----------------------------------------------------------------------------
  24218. X*/
  24219. X
  24220. X#include <stdio.h>
  24221. X#include <string.h>
  24222. X#ifndef unknown_port
  24223. X# ifndef __NeXT__
  24224. X#  include <unistd.h>
  24225. X# else
  24226. X#  include <libc.h>
  24227. X# endif
  24228. X#endif
  24229. X#include <fcntl.h>
  24230. X#include <errno.h>
  24231. X#ifdef unknown_port
  24232. Xextern int errno;
  24233. X#endif
  24234. X#include "defs.h"
  24235. X#include "struct.h"             /* global.h needs it */
  24236. X#include "global.h"             /* misc.c needs it */
  24237. X
  24238. XBOOLEAN tty_echo = TRUE;        /* ditto */
  24239. XFILE    *report  = NULL;        /* ditto */
  24240. Xint    sid     = -1;
  24241. X
  24242. Xextern void setup_string (char *, char *, char *);
  24243. Xextern char *locase (char *);
  24244. Xextern char *upcase (char *);
  24245. X
  24246. Xvoid main ();
  24247. Xint  check (char *);
  24248. Xint  gexit (int);
  24249. X
  24250. Xvoid main ();
  24251. X
  24252. Xchar *s[] = { 
  24253. X  SERVERD_LOCK_FILE, PQUEUE_LOCK_FILE, SERVER_MAIL_FILE, BATCH_FILE, NULL
  24254. X};
  24255. X
  24256. X/*
  24257. X  Test whether any locks exist on the above files plus the mail and moderated
  24258. X  files of each list by other processes.
  24259. X
  24260. X  USER CONTRIBUTED MODIFIED CODE: Warren Burstein.
  24261. X*/
  24262. X
  24263. Xvoid main ()
  24264. X{
  24265. X#ifndef NO_LOCKS
  24266. X  char cmd[MAX_LINE], args[MAX_LINE], file[MAX_LINE], alias[MAX_LINE];
  24267. X  int i, locks = 0;
  24268. X  FILE *fp;
  24269. X
  24270. X  for (i = 0; s[i]; i++)
  24271. X    locks += check (s[i]);
  24272. X
  24273. X  if ((fp = fopen (CONFIG, "r")) == NULL) {
  24274. X    fprintf (stderr, "Cannot open %s\n", CONFIG);
  24275. X    gexit (1);
  24276. X  }
  24277. X
  24278. X  while (! feof (fp)) {
  24279. X    args [0] = RESET (cmd);
  24280. X    fscanf (fp, "%s", cmd);
  24281. X    if (cmd[0] == EOS)
  24282. X      continue;
  24283. X    fgets (args, MAX_LINE - 2, fp);
  24284. X    if (args [0] != EOS && args [strlen (args) - 1] == '\n')
  24285. X      args [strlen (args) - 1] = EOS;
  24286. X
  24287. X    if (strcmp (locase (cmd), "list") == 0 && sscanf (args, "%s", alias) == 1)
  24288. X      upcase (alias),
  24289. X      setup_string (file, alias, LIST_MAIL_FILE),
  24290. X      locks += check (file),
  24291. X      setup_string (file, alias, LIST_MODERATED_F),
  24292. X      locks += check (file);
  24293. X  }
  24294. X  fclose(fp);
  24295. X
  24296. X  if (!locks)
  24297. X    printf ("No files locked.\n"),
  24298. X    gexit (0);
  24299. X  gexit (locks + 1);
  24300. X#else
  24301. X  printf ("File locking mechanism not functional. This mechanism is turned off \
  24302. Xusually when\nfile locking is not supported over NFS. If this system is \
  24303. Xinstalled on a local\nfile system, you may consider undefining the symbol \
  24304. XNO_LOCKS in src/defs.h;\ncheck also with your system manuals to verify that \
  24305. Xfile locking over NFS is\nindeed not supported.\n");
  24306. X  gexit (-1);
  24307. X#endif
  24308. X}
  24309. X
  24310. X/*
  24311. X  Check whether a file is locked.
  24312. X
  24313. X  USER CONTRIBUTED FUNCTION: Warren Burnstein.
  24314. X*/
  24315. X
  24316. Xint check (char *s)
  24317. X{
  24318. X#ifndef NO_LOCKS
  24319. X  int fd, ret = 0;
  24320. X
  24321. X  if (lockf ((fd = open (s, O_RDWR)), F_TLOCK, 0))
  24322. X    if (errno != EBADF)
  24323. X      ret = 1,
  24324. X      printf ("Lock placed on %s\n", s);
  24325. X  close (fd);
  24326. X  return ret;
  24327. X#endif
  24328. X}
  24329. X
  24330. X/*
  24331. X  Required to avoid undefined symbols.
  24332. X*/
  24333. X
  24334. Xint gexit (int exitcode)
  24335. X{
  24336. X  exit (exitcode);
  24337. X}
  24338. *-*-END-of-src/tlock.c-*-*
  24339. echo x - doc/README
  24340. sed 's/^X//' >doc/README <<'*-*-END-of-doc/README-*-*'
  24341. X
  24342. XTo install the man pages permanently on your system you will need to do the
  24343. Xfollowing as superuser:
  24344. X
  24345. X% cp *.nr /usr/man/cat1 <- or wherever the man pages are
  24346. X% cd /usr/man/cat1
  24347. X% compress *.nr
  24348. X% mv server.nr.Z server.1
  24349. X% mv farch.nr.Z farch.1
  24350. X% mv queue.nr.Z queue.1
  24351. X% mv catmail.nr.Z catmail.1
  24352. X% mv list.nr.Z list.1
  24353. X% mv listproc.nr.Z listproc.1
  24354. X% mv serverd.nr.Z serverd.1
  24355. X% mv start.nr.Z start.1
  24356. X% mv ilp.nr.Z ilp.1
  24357. X% chmod 444 server.1 farch.1 queue.1 catmail.1 list.1 listproc.1 serverd.1 \
  24358. X  start.1 ilp.1
  24359. X% vi Index <--- if availbable
  24360. X  add the following lines in Index in the appropriate alphabetic location:
  24361. X    server.1:server:
  24362. X    farch.1:farch:
  24363. X    queue.1:queue:
  24364. X    catmail.1:catmail:
  24365. X    list.1:list:
  24366. X    listproc.1:listproc:
  24367. X    serverd.1:serverd:
  24368. X    start.1:start:
  24369. X    ilp.1:ilp:
  24370. X% vi /usr/man/whatis <-- or whatever file is used when doing man -k
  24371. X  add the following lines in whatis:
  24372. X    server(1)    - ListProcessor system description
  24373. X    farch(1)    - ListProcessor file archiving utility
  24374. X    queue(1)    - ListProcessor mail queue processing
  24375. X    catmail(1)    - ListProcessor mail redirection
  24376. X    list(1)        - ListProcessor mailing list processing
  24377. X    listproc(1)    - ListProcessor request processing
  24378. X    serverd(1)    - ListProcessor system daemon
  24379. X    start(1)    - ListProcessor housekeeper
  24380. X    ilp(1)        - Interactive ListProcessor client
  24381. X
  24382. *-*-END-of-doc/README-*-*
  24383. echo x - doc/catmail.1
  24384. sed 's/^X//' >doc/catmail.1 <<'*-*-END-of-doc/catmail.1-*-*'
  24385. X.\" ListProcessor System
  24386. X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
  24387. X.\"
  24388. X.TH catmail 1 "ListProcessor"
  24389. X.SH NAME
  24390. X\fBcatmail\fP \- append incoming mail to ListProcessor system files
  24391. X.SH SYNOPSIS
  24392. X\fBcatmail\fP {<\fB-L LIST_ALIAS\fP [\fB-m\fP]> | <\fB-r\fP>} [\fB-f\fP]
  24393. X.SH DESCRIPTION
  24394. X\fIcatmail\fP is used to redirect incoming mail to the ListProcessor system
  24395. Xto the appropriate
  24396. Xfiles, according to the flags specified. The files affected are
  24397. XHOMEDIR/requests (a repository for requests), HOMEDIR/lists/*/mail
  24398. X(public messages to be distributed) and HOMEDIR/lists/*/moderated
  24399. X(messages to be screened out by a moderator). \fIcatmail\fP reports the
  24400. Xuser id and user name that is currently executing it; the setuid bit
  24401. Xhas to be set when installed. \fIcatmail\fP first locks the output file
  24402. Xbefore appending to it; if the file cannot be locked after 3 minutes, the
  24403. Xmail is saved under HOMEDIR/lost+found or HOMEDIR/lists/*/lost+found;
  24404. Xboth \fIlist\fP and \fIlistproc\fP
  24405. Xlock their mail files while copying them to a safe place. \fIcatmail\fP will
  24406. Xtime out after 2 minutes to avoid deadlock situations, and the mail message
  24407. Xmay be returned to the sender as undeliverable.
  24408. X.SH OPTIONS
  24409. XThe following command line options are recognized:
  24410. X.TP
  24411. X-L LIST_ALIAS [-m]
  24412. XIf the -m flag is not specified, append to
  24413. XHOMEDIR/lists/\fILIST_ALIAS\fP/mail; otherwise append to
  24414. XHOMEDIR/lists/\fILIST_ALIAS\fP/moderated (see \fIlist(1)\fP).
  24415. X.TP
  24416. X-r
  24417. XAppend to HOMEDIR/requests (overrides -L).
  24418. X.TP
  24419. X-f
  24420. XReformat the message in the process: all lines in the message except the first
  24421. Xstarting with "From " are converted to ">From ".
  24422. X(see also SYSTEM\ SETUP in \fIserver\fP(1)).
  24423. X.SH SEE\ ALSO
  24424. Xlist(1), listproc(1), server(1)
  24425. X.SH AUTHOR
  24426. X.nf
  24427. XAnastasios C. Kotsikonas
  24428. XCopyright (c) 1991-93, Anastasios Kotsikonas
  24429. XComments to tasos@cs.bu.edu
  24430. X.fi
  24431. *-*-END-of-doc/catmail.1-*-*
  24432. echo x - doc/farch.1
  24433. sed 's/^X//' >doc/farch.1 <<'*-*-END-of-doc/farch.1-*-*'
  24434. X.\" ListProcessor System
  24435. X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
  24436. X.\"
  24437. X.TH farch 1 "ListProcessor"
  24438. X.SH NAME
  24439. X\fBfarch\fP \- archive files under the ListProcessor system
  24440. X.SH SYNOPSIS
  24441. X\fBfarch\fP {[\fB-n\fP] [\fB-b\fP | \fB-B\fP] [\fB-s\ size\fP] [\fB-d\ dir\fP] [\fB-p\ password\fP] [\fB-D\ description\fP]\ [\fB-t\ file\fP] [-u]} | {[\fB-r\fP]} [\fB-a\ archive | path-to-archive\fP] [\fB-Z\fP] <\fBfiles\fP>
  24442. X.SH DESCRIPTION
  24443. X\fIfarch\fP is used to archive files under the ListProcessor system 
  24444. Xor remove files already achived, with support provided for private archives.
  24445. XArchives reside under HOMEDIR/archives as subdirectories; the default is
  24446. X\fIlistproc\fP,
  24447. Xand it is also the master archive. Archives are hierarchically
  24448. Xstructured, and each archive has at least two files in its directory:
  24449. X.TP
  24450. XINDEX
  24451. XA list of all subarchives including itself; the format is one line per
  24452. Xarchive with the archive's name followed by the archive's full path, followed
  24453. Xby an optional password:
  24454. X.sp
  24455. Xarchive-name full-path-to-archive-directory [password]
  24456. X.sp
  24457. XThe first entry should be the archive itself;
  24458. Xeach first level subarchive is listed next; then each second level
  24459. Xsubarchive, starting with the first first-level-archive's subarchives,
  24460. Xfollowed by the second first-level-archive's subarchives, etc. No sibling
  24461. Xarchives may have the same name, although there is no such restriction
  24462. Xfor archives on different levels, or "cousin" archives. The latter archives
  24463. Xare distinguished by the relative path needed to access them (see
  24464. X\fIserver\fP(1) for more information).
  24465. X.TP
  24466. XDIR
  24467. XA list of files available from that archive; the format is one line
  24468. Xper file with the file name followed by the number of parts it may be
  24469. Xsplit into, followed by the number of bytes of each of the parts, followed
  24470. Xby the full path to the directory these parts can be found, followed
  24471. Xby a short descriptive message about the file (optional). The descriptive
  24472. Xmessage may span several lines; each line (except the last) should end 
  24473. Xwith a '\\':
  24474. X.sp
  24475. X.nf
  24476. Xfile nparts size-of-each-part+ full-path-to-directory [description [\\]]
  24477. X[multiple description lines [\\]]*
  24478. X.fi
  24479. X.sp
  24480. XThe number of parts the file is split into may be -1 to indicate that
  24481. Xthis is a binary file.
  24482. X.PP
  24483. X\fIfarch\fP reports on the action taken on each input file: whether it
  24484. Xwas split (and how many parts), whether it was uuencoded, whether all files
  24485. Xhave been tar'red into a single one, the archive this file was archived under,
  24486. Xand the directory the output file(s) (if any) has/have been placed. It
  24487. Xalso reports when the input files are tarred.
  24488. X.SH OPTIONS
  24489. XThe following command line options are recognized:
  24490. X.TP
  24491. X-n
  24492. XDo not split files when archiving them. The default is to split them with
  24493. Xeach part not larger than the specified size (see the -s option below).
  24494. X.TP
  24495. X-b
  24496. XInput files are binary; they are uuencoded before archived.
  24497. X.TP
  24498. X-B
  24499. XInput files are binary; they are neither uuencoded nor split.
  24500. X.TP
  24501. X-s size
  24502. XSpecify the maximum \fIsize\fP in kilobytes of each of the subparts 
  24503. X(default is 64).
  24504. X.TP
  24505. X-d dir
  24506. XSpecify the \fIdir\fPectory that the output files are to be placed; if
  24507. Xleft out, it defaults to the specified archive's directory
  24508. X(HOMEDIR/archives/listproc if the archive is left out as well).
  24509. XIf the directory (and all of its subdirectories, if any) does not exist,
  24510. Xit will be created.
  24511. X.TP
  24512. X-p password
  24513. XWhen a new archive is to be created, and that archive is to be private,
  24514. Xspecify the access password.
  24515. X.TP
  24516. X-D description
  24517. XPut \fIdescription\fP (most likely surrounded by single quotes) in the
  24518. XDIR file as explanatory comment about the archived file. This option does
  24519. Xnot make much sense when archiving more than one file at the same time.
  24520. X.TP
  24521. X-t file
  24522. XInput files are tar'red into \fIfile\fP which is then archived (the -b flag
  24523. Xis automatically turned on). Turning on the -B flag will prevent uuencoding
  24524. Xof the tar file. Note that whatever the path to \fIfile\fP may
  24525. Xbe, it will be moved to the specified directory as specified by the -d flag.
  24526. X.TP
  24527. X-u
  24528. XUpdate existing files while archiving; preserve the current comment fields,
  24529. Xunless -D is explicitly used.
  24530. X.TP
  24531. X-r
  24532. XRemove the specified file(s) from the specified archive (see below), or the
  24533. Xdefault one; it has higher priority than all of the options above.
  24534. X.TP
  24535. X-a archive | path-to-archive
  24536. XSpecify the \fIarchive\fP that the input files will be archived under (default
  24537. Xis listproc). Archives on different levels of the hierarchy may have the
  24538. Xsame name and in this case a \fIpath-to-archive\fP may be specified to
  24539. Xdistinguish between them;
  24540. X\fIpath-to-archive\fP has the form \fIarchive[/archive[/archive...]]\fP
  24541. X(see also \fIserver(1)\fP). If any of the archives in the path do not exist,
  24542. Xthey will be created with the necessary files.
  24543. X.TP
  24544. X-Z
  24545. XTurn off file compression.
  24546. X.PP
  24547. XFile names in the DIR file have to be unique and \fIfarch\fP will not
  24548. Xarchive duplicate files.
  24549. X.SH ARCHIVING\ A\ FILE
  24550. X\fIfarch\fP by default splits the input files if necessary
  24551. X(or the tar file, if any),
  24552. Xinto files of maximum size as specified. Each part
  24553. Xwill contain as many complete lines from the original input file as possible,
  24554. Xwithout exceeding the specified size. Binary files (including the tar file)
  24555. Xare uuencoded before they are archived unless the -B option is specified,
  24556. Xand all archived files are compressed, if possible.
  24557. X.SH ADDING\ A\ NEW\ ARCHIVE
  24558. X.TP
  24559. Xautomatically
  24560. XSimply specify the new archive as argument to the -a flag. All necessary DIR
  24561. Xand INDEX files as well as all required directories will be created, and
  24562. Xall parent archives will be updated.
  24563. X.TP
  24564. Xby hand
  24565. XStep 1
  24566. X.sp
  24567. XCreate a directory under HOMEDIR/archives or under an existing
  24568. Xarchive's directory (beware of the hierarchy structure), naming the
  24569. Xdirectory after the archive.
  24570. XThe archive's name should be unique among its siblings on that level in the
  24571. Xhierarchy (besides, mkdir will not let specify a name that already exists).
  24572. X.sp
  24573. XStep 2
  24574. X.sp
  24575. XEdit the master archive's index file (HOMEDIR/archives/listproc/INDEX) and
  24576. Xadd the new archive along with its path (and optional password -- see below)
  24577. Xat the proper place in the file, making sure you adhere to the
  24578. Xrules about hierarchy outined above. The first line of every INDEX
  24579. Xfile should be the archive itself. Also edit (add to) every ancestor archive's
  24580. XINDEX file, if the new archive is not the default, again making sure you adhere
  24581. Xto the same rules.
  24582. X.sp
  24583. XStep 3
  24584. X.sp
  24585. XCreate a new INDEX file in the new archive's directory and put an entry
  24586. Xfor itself.
  24587. X.sp
  24588. XStep 4
  24589. X.sp
  24590. XCreate an empty DIR file in the new archive's directory.
  24591. X.SH PRIVATE\ ARCHIVES
  24592. XPrivate archives are archives that require a password for obtaining
  24593. Xindices and/or files from them. To make an archive private, simply
  24594. Xappend a password (case does not matter) after its full path specification
  24595. Xin every INDEX file the archive is defined (its own plus all ancestors' --
  24596. Xthe same password has to be used in all of these files). Then, that 
  24597. Xpassword has
  24598. Xto be made known to all users who are to be granted access to this archive.
  24599. XNote that all files in the same private archive can be obtained with the
  24600. Xsame single password.
  24601. X.SH EXAMPLES
  24602. XArchive src/data and src/data2 under archive listproc (the default),
  24603. Xusing a maximum file size of 1K; the output file(s) will be placed in /tmp/tmp:
  24604. X.sp
  24605. X.nf
  24606. X.in +2
  24607. X% farch -s 1 -d /tmp/tmp src/data src/data2
  24608. X.fi
  24609. X.in -2
  24610. X.sp
  24611. XArchive /etc/hosts under archive unix (that is listproc/unix) -- the -n
  24612. Xflag is used to avoid writing split parts to /etc which is doomed to fail:
  24613. X.sp
  24614. X.nf
  24615. X.in +2
  24616. X% farch -n -a unix -d /etc -p private /etc/hosts
  24617. X.fi
  24618. X.in -2
  24619. X.sp
  24620. XArchive /etc/password under archive pub/unix (that is listproc/pub/unix):
  24621. X.sp
  24622. X.nf
  24623. X.in +2
  24624. X% farch -n -a pub/unix -d /etc /etc/passwd
  24625. X.fi
  24626. X.in -2
  24627. X.sp
  24628. XTar and archive all files in /usr/src to the default archive and place the
  24629. Xtar file under /tmp/tmp:
  24630. X.sp
  24631. X.nf
  24632. X.in +2
  24633. X% farch -t HOMEDIR/source -d /tmp/tmp /usr/src/*.c
  24634. X.fi
  24635. X.in -2
  24636. X.sp
  24637. XDescriptive messages about these files are added manually into the archive's
  24638. XDIR file. However, the -D option can be used to specify a string as follows:
  24639. X.sp
  24640. X.nf
  24641. X.in +2
  24642. X% farch -D 'ListProcessor system files' -t ulistproc.tar -n -d /usr/server /usr/server/*
  24643. X.SH UPGRADING
  24644. XIf you are upgrading from:
  24645. X.TP
  24646. X5.5
  24647. XThe -B, -p, -r and -D options are new; functionality is the same.
  24648. X.TP
  24649. X5.41 or less
  24650. XEvery DIR file should now include the size of each of the parts of every
  24651. Xfile, placed between the number of parts and the path name.
  24652. X.sp
  24653. XThe -a option has been extended to accept paths to archives.
  24654. X.SH RESTRICTIONS
  24655. X\-
  24656. XArchive names and input files must use only lower case characters of the
  24657. Xalphabet.
  24658. X.SH WARNINGS
  24659. X\-
  24660. XInput files that are to be tar'red should only include relative path names;
  24661. Xotherwise the end user may not be able to extract them.
  24662. X.sp
  24663. X\-
  24664. XThe tar file should not be any of the input files.
  24665. X.SH SEE\ ALSO
  24666. Xserver(1)
  24667. X.SH AUTHOR
  24668. X.nf
  24669. XAnastasios C. Kotsikonas
  24670. XCopyright (c) 1991-93, Anastasios Kotsikonas
  24671. XComments to tasos@cs.bu.edu
  24672. X.fi
  24673. *-*-END-of-doc/farch.1-*-*
  24674. echo x - doc/ilp.1
  24675. sed 's/^X//' >doc/ilp.1 <<'*-*-END-of-doc/ilp.1-*-*'
  24676. X.\" ListProcessor System
  24677. X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
  24678. X.\"
  24679. X.TH ilp 1 "ILP 2.1"
  24680. X.SH NAME
  24681. X\fBilp\fP \- Interactive ListProcessor client
  24682. X.SH SYNOPSIS
  24683. X\fBilp\fP [\fB-v\fP] [\fB-t timeout\fP] [\fB-b buffer-size in K\fP] \fBhost\fP [\fBport\fP]
  24684. X.SH DESCRIPTION
  24685. X\fIilp\fP is a client that connects to the specified \fIhost\fP's
  24686. XInteractive ListProcessor port (372) for a live session -- i.e. for
  24687. Xprocessing requests live. Another \fIport\fP
  24688. Xmay be specified if necessary. The \fIhost\fP may be a host name, or an 
  24689. XIP address.
  24690. X.PP
  24691. XUpon connection establishment, the protocol attempts to set the user's
  24692. Xprivileges during the session by requesting an email address and a password.
  24693. XThese are used to determine whether the user is to be granted system,
  24694. Xowner, subscriber or casual user privileges. If the user provides
  24695. Xhis owner email address and his list's password, he will be granted
  24696. Xowner privileges. If he provides an email address that he uses for subscription
  24697. Xto a list, along with the password he uses for that list, he will be granted
  24698. Xsubscriber privileges. The system provides a brief listing of all valid
  24699. Xrequests the user may issue during the session. If no email address is
  24700. Xprovided, or no matches are found, the user is restricted to a few
  24701. Xrequests.
  24702. X.PP
  24703. XRequests for remote lists are serviced by attempting to connect
  24704. Xto the ILP server(s) (if any) of the system(s) that handle those lists.
  24705. X.PP
  24706. XThe ILP server recognizes the following special requests:
  24707. X.TP
  24708. Xquit/exit
  24709. XEnd the session.
  24710. X.TP
  24711. X?/privileges
  24712. XGet a brief listing of all valid requests.
  24713. X.TP
  24714. Xtimeleft
  24715. XPrints the remaining time in seconds.
  24716. X.TP
  24717. X&<new-line>
  24718. XInput continues on the next line.
  24719. X.TP
  24720. Xbinary
  24721. XSwitch to binary mode when transferring files.
  24722. X.TP
  24723. Xascii
  24724. XSwitch to ASCII mode when transferring files.
  24725. X.TP
  24726. X< filename
  24727. XInput is taken from the specified file. Each line will be interpreted as
  24728. Xa separate request, unless the file is specified in conjunction with a
  24729. X\fIput\fP request. If the '<' is to be used literally it
  24730. Xmust be escaped with '\\' or enclosed in quotes.
  24731. X.TP
  24732. X> filename
  24733. XRedirect the reply to the request to the specified file. Error messages
  24734. X(such as rejections due to invalid requests, etc.) are not redirected.
  24735. XWhen a file is downloaded via a \fIget\fP request, this will override the
  24736. Xfile name that will be saved under. If the '>' is to be used literally it
  24737. Xmust be escaped with \\ or enclosed in quotes.
  24738. X.TP
  24739. X>> filename
  24740. XSame as above, but the reply is appended to the specified file.
  24741. X.TP
  24742. X| prog [args]
  24743. XThe output of the request is piped to \fIprog\fP; this is similar to a 
  24744. XUNIX pipe. \fIprog\fP may be any valid UNIX command, including other pipes, file
  24745. Xredirections, etc. Since '<' has higher precedence in this context, you
  24746. Xshould escape any '<' characters intended to be used by the pipe, otherwise
  24747. Xthe system will assume you are feeding it batched requests. Quotes may also
  24748. Xbe used to protect these characters.
  24749. X.SH OPTIONS
  24750. XThe following options are recognized:
  24751. X.TP
  24752. X-v
  24753. XTurn verbose mode on; the server reply codes are echoed along with
  24754. Xpredetermined messages.
  24755. X.TP
  24756. X-t timeout
  24757. XThe default time out for a server response is 180 seconds; to reset
  24758. Xuse the -t flag. This timeout should not be confused with the
  24759. Xremaining time of a connection.
  24760. X.TP
  24761. X-b buffer-size
  24762. XThe default socket buffer size is 8K; to reset use the -b flag
  24763. X(the argument specifies kilobytes).
  24764. X
  24765. X.SH USER\ PRIVILEGES
  24766. XCasual users may only issue help, information, recipients and statistics
  24767. Xfor nonprivate lists, lists, index, get, view, search and release requests.
  24768. XSubscriber privileges also include the set, run, unsubscribe and which requests.
  24769. XOwners may, in addition, issue all of their administrative requests.
  24770. X.PP
  24771. XIssue a 'help live' request when you first connect to an ILP server.
  24772. X.SH RESTRICTIONS
  24773. XThe connection duration is limited to a server-imposed limit.
  24774. XAfter that, a connection may be broken by the server as necessary.
  24775. XA connection will not be broken during a transfer.
  24776. X.SH EXAMPLES
  24777. X.nf
  24778. Xrequest> put ermis ermis1 subscribers </usr/server/backup/lists/ERMIS/subs >out
  24779. X.sp
  24780. Xrequest> get listproc example.dat 1 3 >> out
  24781. X.sp
  24782. Xrequest> get listproc example.dat
  24783. X.sp
  24784. Xrequest> index ilp > ILP
  24785. X.sp
  24786. Xrequest> < /tmp/batched.requests
  24787. X.sp
  24788. Xrequest> index | more
  24789. X.sp
  24790. Xrequest> lists | cut -d ' ' -f1,2 | more
  24791. X.sp
  24792. Xrequest> search ilp "\\>\\> out"
  24793. X.sp
  24794. X.fi
  24795. XIn this last example, we escape each > to protect it from being interpreted
  24796. Xas a regular expression separator, and enclose the whole pattern in quotes
  24797. Xto protect the \\>\\> from being evaluated.
  24798. X.SH FILES
  24799. X.TP
  24800. Xilp.c, ilp.h
  24801. XSource code for the client. See ilp.c for compile options.
  24802. X.TP
  24803. Xilpp.h
  24804. XDefinition of the Interactive ListProcessor Protocol.
  24805. X.TP
  24806. Xmakefile
  24807. Xmakefile to build \fIilp\fP. \fIilp\fP is written with BSD-style signal
  24808. Xhandling, therefore on some hosts (like IBM AIX) you will have to link with
  24809. XBSD versions of signal(2), socket(3N), and fcntl(2). Platforms that
  24810. Xhave the <sys/select.h> and <ulimit.h> header files should compile
  24811. Xwith -DHAVE_SELECT_H and/or -DHAVE_ULIMIT_H. SCO ports should compile with
  24812. X-Dsco. Always link with libraries that provide DNS support (resolver linked
  24813. Xin).
  24814. X.SH BUGS
  24815. XPlease report any bugs or enhancements to tasos@cs.bu.edu
  24816. *-*-END-of-doc/ilp.1-*-*
  24817. echo x - doc/list.1
  24818. sed 's/^X//' >doc/list.1 <<'*-*-END-of-doc/list.1-*-*'
  24819. X.\" ListProcessor System
  24820. X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
  24821. X.\"
  24822. X.TH list 1 "ListProcessor"
  24823. X.SH NAME
  24824. X\fBlist\fP \- process a specified ListProcessor mailing list
  24825. X.SH SYNOPSIS
  24826. X\fBlist -L\fP\ <\fBLIST_ALIAS\fP> [\fB-1\fP] [\fB-e\fP] [\fB-s\fP] [\fB-p\fP] [\fB-P\fP] [\fB-m\ #\fP] [\fB-f\fP] [\fB-r\fP] [\fB-M\fP] [\fB-d\fP] [\fB-i\fP <\fBaddress\fP>] [\fB-v\fP] [\fB-Z\fP] [\fB-D\fP]
  24827. X.SH DESCRIPTION:
  24828. X\fIlist\fP distributes the message(s) sent to \fIlist_alias@your-domain\fP;
  24829. Xthe file ".ignored" in the list's subdirectory is used to filter out any
  24830. Xunwanted messages (see below).
  24831. X.PP
  24832. XMessages from mailer daemons are forwarded to the list's owner and screened
  24833. Xlooking for delivery errors (in which case appropriate action is taken --
  24834. Xusers are either immediately removed from the list, or after a series of
  24835. Xdelivery errors within a certain time frame -- entries removed from the
  24836. Xsystem's files are placed into HOMEDIR/lists/*/removed.users and
  24837. XHOMEDIR/lists/*/removed.alias files),
  24838. Xwhereas messages
  24839. Xfrom non-subscribers are returned to the original senders (the -f flag
  24840. Xoverrides this). Messages whose first line looks like a ListProcessor request
  24841. Xare bounced back to the sender.
  24842. X.PP
  24843. XMessages from news groups are distributed only to local
  24844. Xsubscribers and peer lists. Messages from peers are distributed to local
  24845. Xsubscribers and possibly posted to news groups. Finally, messages from
  24846. Xlocal subscribers are either distributed locally, copies are sent to all peers,
  24847. Xand are possibly posted to news groups, or are forwarded to the list's
  24848. Xowner for screening if the list is moderated.
  24849. X.PP
  24850. XAll distributed messages 
  24851. X(i.e. legitimate messages from subscribers, peers and news groups -- not
  24852. Xrejected, ignored or error messages)
  24853. Xare automatically archived in HOMEDIR/lists/*/archive. In contrast,
  24854. Xthe files HOMEDIR/lists/*/mbox contain all messages sent to these
  24855. Xlists (including, error, rejected and ignored messages).
  24856. X.PP
  24857. XEmail from one or more subscribers may be selectively distributed to an
  24858. Xalternate list of recipients, by way of restricted mail (see below),
  24859. Xin which case mail will not be distributed to the regular subscribers.
  24860. X.PP
  24861. XWhen the system is for some reason aborted while making a delivery, a
  24862. Xbuilt-in mechanism allows it to resume from the point it left off.
  24863. X.SH OPTIONS
  24864. XThe following command line options are recognized:
  24865. X.TP
  24866. X-L LIST_ALIAS
  24867. XProcess any messages sent to this \fILIST_ALIAS\fP -- \fILIST_ALIAS\fP should
  24868. Xbe in capital letters.
  24869. X.TP
  24870. X-1
  24871. XExecute only once; process the mailing list and return control to
  24872. X\fIserverd\fP(1); any new messages that may have arrived in the meantime will
  24873. Xbe processed at a later time. Without this option, \fIlist\fP will be
  24874. Xlistening for messages for the specified list for ever. \fIserverd\fP(1)
  24875. Xuses this option by default when spawning \fIlist\fP.
  24876. X.TP
  24877. X-e
  24878. XEcho reports to the screen; it has no effect if the system has been compiled
  24879. Xwith -DSYSLOG.
  24880. X.TP
  24881. X-s
  24882. XBy default, only subscribers can send messages to a list. This option
  24883. Xturns off subscription checking.
  24884. X.TP
  24885. X-p
  24886. XBy default, replies to messages posted to news groups go to the list; 
  24887. Xthis option forces replies to be forwarded to the original author.
  24888. X.TP
  24889. X-P
  24890. XBy default, replies to messages sent to subscribers and peers go to the
  24891. Xlist; this option forces replies to be forwarded to the original author.
  24892. X.TP
  24893. X-m number
  24894. XNormally, each outgoing message has one recipient. This flag switches to
  24895. Xmulti-recipient outgoing messages and specifies the \fInumber\fP of recipients
  24896. Xto be included in these messages.
  24897. X.TP
  24898. X-f
  24899. XForward any messages from non-subscribers to the list's owner. By default,
  24900. Xthey are returned to the sender.
  24901. X.TP
  24902. X-r
  24903. XRestricted mail: \fIlist\fP will look at the ".restricted" file (see
  24904. Xbelow) to get the name of the alternate recipients file. If the sender
  24905. Xis listed in that ".restricted" file, his messages will be distributed
  24906. Xto users listed in the alternate recipients file.
  24907. X.TP
  24908. X-M
  24909. XThe list is moderated;
  24910. Xall incoming messages not from the owner(s) are forwarded to the
  24911. Xlist's primary owner for review and editing. The owner then sends back the
  24912. Xones that are approved for posting (for an alternate scheme see the
  24913. XMODERATED\ LISTS section below).
  24914. X.TP
  24915. X-d
  24916. XForce a digest to be distributed. This flag is internally used by
  24917. X\fIserverd\fP(1) when digest time has been reached for this list.
  24918. X.TP
  24919. X-i address
  24920. XSend a partial digest to \fIaddress\fP (what has accumulated so far).
  24921. XThis flag is internally used by
  24922. X\fIlistproc\fP(1) when the user identified by \fIaddress\fP changes his
  24923. X\fImail\fP mode from \fIdigest\fP to something else. Note that when 
  24924. Xthe time arrives for the current digest to be distributed, this
  24925. Xuser will get duplicate messages.
  24926. X.TP
  24927. X-v
  24928. XPrint version information.
  24929. X.TP
  24930. X-Z
  24931. XTurn off file compression when archiving messages.
  24932. X.TP
  24933. X-D
  24934. XTurns debugging on. When the \fIsystem\fP mailmethod is used (see \fIserver(1)\fP), a
  24935. Xcopy of the last SMTP transaction can be found in the files
  24936. XHOMEDIR/sent and HOMEDIR/received.
  24937. X.SH ADDING\ A\ NEW\ LIST
  24938. XTo add a new list, first shut the system down by executing \fIstart\fP(1):
  24939. X.sp
  24940. X.in +2
  24941. X\fI% start -k\fP
  24942. X.in -2
  24943. X.sp
  24944. XThen edit the \fIconfig\fP file and add a line defining the
  24945. Xnew list -- you may wish to add a comment and/or disable a few requests also.
  24946. XA new alias has to be set up in /etc/aliases, /usr/lib/aliases
  24947. Xor /usr/ucblib/aliases of the following form:
  24948. X.nf
  24949. X.sp
  24950. Xlist_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f"
  24951. X.sp
  24952. X.fi
  24953. XIf using surrogate mail, then the alias is defined as follows in
  24954. X/etc/mail/mailsurr:
  24955. X.sp
  24956. X.nf
  24957. X\'.+' 'list_alias' '<S=0;F=1-255;C=*;HOMEDIR/catmail -L LIST_ALIAS -f'
  24958. X.sp
  24959. X.fi
  24960. XNote that \fIlist_alias\fP is all lower case and \fILIST_ALIAS\fP is all
  24961. Xupper case. In this case \fIcatmail\fP(1) appends incoming mail to the list's
  24962. Xmail file (HOMEDIR/lists/LIST_ALIAS/mail).
  24963. XAlso keep in mind the case of reformatting messages as described in
  24964. X\fIcatmail\fP(1).
  24965. X.PP
  24966. XFinally, restart the system. At this point, the file ".ignored" in the
  24967. XHOMEDIR/lists/LIST_ALIAS directory may be edited to add more
  24968. Xunwanted senders. You should also edit the files ".welcome" and ".info"
  24969. Xin the list's subdirectory; the former is included in the return message
  24970. Xfor a new subscription request for that list, and the latter
  24971. Xis included in the return message for an \fIinformation\fP request for that
  24972. Xlist (see \fIlistproc\fP(1)). These files may be simple text files, or shell
  24973. Xscripts (see the HELP section in \fIserver(1)\fP).
  24974. X.SH ADDING\ A\ PEER\ LIST
  24975. XPeer lists are mailing lists that happen to be subscribers to one
  24976. Xor more of your own mailing lists; they handle local distribution of
  24977. Xmessages just like you do at your own site. Peer lists can be mutual
  24978. Xsubscribers, so that a message originating in a peer list gets distributed
  24979. Xover there locally, and a copy is sent to the other for local distribution,
  24980. Xand vice versa. An automatic mechanism is provided for avoiding loops.
  24981. XA peer list can be added to
  24982. Xa local mailing list by using the script \fIpeer\fP:
  24983. X.sp
  24984. Xpeer\ <LIST_ALIAS>\ <remote\ alias>\ <peer\ address>\ <remote\ ListProcessor\ address>
  24985. X.sp
  24986. Xwhere \fILIST_ALIAS\fP is a local list alias in capital letters, 
  24987. X\fIremote\ alias\fP is the peer's alias on the remote machine,
  24988. X\fIpeer\ address\fP is taken
  24989. Xfrom the first line of the header of a test message sent to your host
  24990. Xby the peer 
  24991. X(the first line may be something like: "From peer@other-domain" -- see also
  24992. Xthe discussion about aliases below), and
  24993. X\fIremote\ ListProcessor\ address\fP is the full email address of the
  24994. Xremote request-handler.
  24995. X.PP
  24996. XHere is an example for
  24997. Xestablishing connection between two peer lists a@domain1 and b@domain2:
  24998. XThe \fImanager\fP at domain1 issues the following command:
  24999. X.sp
  25000. X.nf
  25001. Xpeer a b b@domain2 listproc@hdomain2
  25002. X.fi
  25003. X.sp
  25004. XThe \fImanager\fP at domain2 issues the following command:
  25005. X.sp
  25006. X.nf
  25007. Xpeer b a a@domain1 listproc@domain1
  25008. X.fi
  25009. X.sp
  25010. XOnce these two commands are issued the connection is automatically
  25011. Xset up.
  25012. XPeer lists should make sure that only one of them posts
  25013. Xto the same news group(s), and that only one of them receives articles
  25014. Xfrom the same news group(s)/gateway(s).
  25015. XLists handled by the same server cannot be mutual
  25016. Xpeers. Finally, peer lists should not be regular subscribers (the
  25017. X\fIpeer\fP script places them in a file called ".peers").
  25018. X.SH NEWS\ GROUPS\ AND\ GATEWAYS
  25019. XA mailing list may be linked with one or more news groups (or gateways) 
  25020. Xfrom which
  25021. Xit may receive messages for local distribution, and/or send messages to
  25022. Xthe newsgroup(s) for posting \-\- in this case only messages from
  25023. Xregular subscribers and peers are sent for posting, i.e. no news messages
  25024. Xwill be posted to any news groups (or gateways). 
  25025. XA news group or gateway is linked using the script \fInews\fP:
  25026. X.sp
  25027. X.ce
  25028. Xnews\ <LIST_ALIAS>\ <news\ group>\ <email\ address>\ <mode>
  25029. X.sp
  25030. Xwhere \fILIST_ALIAS\fP is a local list alias (in capital letters) 
  25031. Xthat is being linked to the news group, \fInews\ group\fP is the name
  25032. Xof the news group (used only when posting) e.g. misc.test,
  25033. X\fIemail\ address\fP is the address of the backbone or moderator of 
  25034. Xthe news group, or the gateway, and it is taken
  25035. Xfrom the first line of the header of a test message sent to your host
  25036. Xby the group (the first line may be something like: 
  25037. X"From gateway@foo ..." -- see also the discussion about aliases below);
  25038. X\fImode\fP is one of the following:
  25039. X.TP
  25040. Xreceive
  25041. XThe list will only be receiving messages from this news group and never
  25042. Xpost to it. This allows access to the group (or gateway)
  25043. Xto send articles to the list.
  25044. X.TP
  25045. Xsend_receive
  25046. XThe list may be receiving messages from this news group, and it will post
  25047. Xto it any messages from regular subscribers and peer lists (messages from
  25048. Xnews groups are never posted to other news groups). This also
  25049. Xallows access to the group (or gateway) to send articles to the list.
  25050. X.PP
  25051. XOf course, the news group's
  25052. Xcaretaker has to be notified of the list's address so that articles will indeed
  25053. Xbe sent to it. Finally, news groups should not be regular subscribers (the
  25054. X\fInews\fP script places them in a file called ".news"). 
  25055. X.PP
  25056. XIf the config option \fIpost_mail\fP is used,
  25057. Xthe system will use \fIinews\fP for posting, and it assumes that the
  25058. Xpath to it is /usr/lib/news/inews, so make sure that \fIinews\fP resides there,
  25059. Xor a link exists to it. In this case, the group's name is used for posting
  25060. X(e.g. misc.test). If instead \fIgate_mail\fP is defined, messages will
  25061. Xbe sent via email to news gateways (using the \fIemail\ address\fP)
  25062. X-- the \fInews\ group\fP name has no significance in this case.
  25063. X.SH MODERATED\ LISTS
  25064. XThe system supports two schemes for moderating lists. The first scheme uses
  25065. Xthe -M flag to \fIlist\fP(1), and in this case messages not from the
  25066. Xlist's owner(s) are forwarded to the list's primary owner for review;
  25067. Xthe owner then sends back the approved (and possibly edited) ones.
  25068. X.PP
  25069. XThe second scheme uses the -m flag to \fIcatmail\fP(1). In this case, the
  25070. Xlist's alias is changed slightly in the aliases file:
  25071. X.nf
  25072. X.sp
  25073. Xlist_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f -m"
  25074. X.sp
  25075. X.fi
  25076. Xand similarly if using surrogate mail.
  25077. X\fIlist\fP(1) distributes messages from a file called \fImail\fP; by having
  25078. Xincoming messages redirected to the file \fImoderated\fP (the effect of the
  25079. X-m flag to \fIcatmail\fP(1)), the list's owner may \fIapprove\fP or
  25080. X\fIdiscard\fP any number of these messages (see \fIlistproc\fP(1)).
  25081. XWhenever a new
  25082. Xmail message arrives for a moderated list, a copy is sent to the list's
  25083. Xowner with instructions for approving or discarding it. These instructions
  25084. Xinclude a unique tag number for identifying that message. When a message
  25085. Xis approved, it is transferred to the \fImail\fP file for later delivery,
  25086. Xand when discarded, it is simply removed from the
  25087. X\fImoderated\fP file. This scheme cuts down on mail traffic.
  25088. X.SH RESTRICTED\ MAIL
  25089. XWhen the -r flag is used with \fIlist\fP(1), for every message received its
  25090. Xsender is checked against a list of "restricted" email addresses, in the
  25091. Xfile ".restricted" in the list's directory -- a
  25092. Xsubset of the ".subscribers" file. If a match is found, mail is
  25093. Xforwarded to the people listed in the file following this email
  25094. Xaddress. If no match is found, the message is distributed to the
  25095. Xregular subscribers. Note that the alternate recipients file should
  25096. Xbe in the same format as the ".subscribers".
  25097. X.SH .SUBSCRIBERS
  25098. XThe format is as follows:
  25099. X.PP
  25100. XOne entry per line; each entry is the full email address of the subscriber
  25101. Xas it appears in the "From " field, followed by the word "ACK" (in which
  25102. Xcase his/her message will be sent back to him/her as an acknowledgement),
  25103. X"NOACK" (the opposite), "POSTPONE" (no mail will be sent until the
  25104. Xuser changes mode again),
  25105. Xor "DIGEST" (digests are periodically sent), followed by a string that
  25106. Xplays the role of the user's password, followed by either "YES" or "NO"
  25107. Xwhich are the values of the conceal attribute, followed by the subscriber's
  25108. Xname. See also \fIlistproc\fP(1).
  25109. X.SH .RESTRICTED
  25110. XThe format is as follows:
  25111. X.PP
  25112. XOne entry per line; each entry is the full email address of the
  25113. Xsubscriber, followed by a file name where email addresses of recipients
  25114. Xare listed (just like in the ".subscribers" file). Example:
  25115. X.sp
  25116. X.ce
  25117. Xjdoe@foo.bar.com  HOMEDIR/lists/LIST_ALIAS/.recipients
  25118. X.sp
  25119. XIf the recipient file given is the word "NONE", then no one will receive
  25120. Xany messages.
  25121. X.SH .ALIASES
  25122. XIt is possible that a subscriber's/peer's/news group's/gateway's email
  25123. Xmay arrive using a different path than registered, which may raise
  25124. Xsubscription issues. To work around this,
  25125. Xeach list provides a ".aliases" file in its subdirectory, which may contain
  25126. Xalternate email addresses to be used when checking for subscription. The
  25127. Xformat is one line per alias with the following information:
  25128. X.sp
  25129. X.ce
  25130. Xalias-address address-as-subscribed
  25131. X.sp
  25132. XPlease note that only the subscribed address is used for sending out
  25133. Xemail (see next section about regular expressions).
  25134. X.PP
  25135. XThe aliased address may be a regular expression with egrep(1) style syntax,
  25136. Xin which case
  25137. Xthe following characters have special meanings: '~', if leading the
  25138. Xregular expression it reverses its meaning; '|' and '&' separate multiple
  25139. Xregular expressions (logical OR and AND); '<' '>' group regular expressions
  25140. X(we preserve the meaning of the parentheses from ed(1), and remove the
  25141. Xmeaning of < and > from ed(1) since in the ListProcessor context they are either
  25142. Xthe default, or inappropriate).
  25143. XThese can be used literally by escaping them
  25144. Xwith '\\'. In addition, the following characters should be defined
  25145. Xin matched pairs: (), <>, [], "". For example:
  25146. X.sp
  25147. X.ce
  25148. Xjdoe@.*\\.bar\\.com jdoe@foo.bar.com
  25149. X.sp
  25150. Xwill enable this user to send messages from any machine in his local
  25151. Xnetwork and receive replies at foo.bar.com -- keep in mind that a '.'
  25152. Xmatches exactly one character, and '.*' matches zero or more characters.
  25153. XIn a more complicated example:
  25154. X.sp
  25155. X.ce
  25156. X~jdoe@cc.*|jdoe@....*\\.bar\\.com jdoe@foo.bar.com
  25157. X.sp
  25158. Xwill match if jdoe sends a message from a machine whose name does not start
  25159. Xwith 'cc', or from a machine whose name has at least 3 characters.
  25160. X.PP
  25161. XIf certain parts of the regular expression are parenthesized, then the
  25162. Xstrings that matched the subexpressions can be used in
  25163. Xthe 'address-as-subscribed' to form new return addresses; these matched
  25164. Xstrings are accessed by \fI\\n\fP where \fIn\fP is a digit between 1 and
  25165. X9. For example, if the sender is:
  25166. X.sp
  25167. X.ce
  25168. XGATE!HOP!USER@UUCP.SOME.COM
  25169. X.sp
  25170. Xand the entry in the ".aliases" file reads:
  25171. X.sp
  25172. X.ce
  25173. X[^!@]*!([^!@.]*)!([^!@]*)@.*    \\2@\\1.UUCP
  25174. X.sp
  25175. Xthen what will be returned as 'address-as-subscribed' is:
  25176. X.sp
  25177. X.ce
  25178. XUSER@HOP.UUCP
  25179. X.sp
  25180. XThis way you can map addresses coming in via various gateways to steady ones
  25181. X(\\2 refers to the second set of parentheses, and \\1 to the first).
  25182. XManagers may edit HOMEDIR/src/regex.c to test regular expression
  25183. Xbehavior, introduce ls(1) style meanings to the * and ? wild characters,
  25184. Xundefine ed(1) special characters, and enforce strict egrep(1) syntax (remove
  25185. Xthe meanings of ~ & < and >).
  25186. X.PP
  25187. XRegular expressions should be used with caution for obvious reasons.
  25188. X.PP
  25189. XIf someone is experiencing subscription
  25190. Xproblems, you may wish to add their alternate email address(es) in this
  25191. Xfile. This includes regular subscribers, news groups, peers and gateways.
  25192. XIf the sender is also a restricted subscriber, do not forget to put
  25193. Xanother entry in ".restricted" with the new alternate address. Any
  25194. Xnumber of aliases may be defined for each individual address.
  25195. X.PP
  25196. XIn addition, a ".aliases" file is also provided for ListProcessor
  25197. Xrequests and is under HOMEDIR. The same syntax is used, but each
  25198. Xentry has a slightly different meaning:
  25199. X.sp
  25200. X.ce
  25201. Xaddress-as-arrived address-used-for-reply
  25202. X.sp
  25203. XIn this case, \fIaddress-used-for-reply\fP will be used to reply to all
  25204. Xrequests sent in by \fIaddress-as-arrived\fP. A user may have any
  25205. Xnumber of aliases, but only the first one matching
  25206. X\fIaddress-as-arrived\fP will be used. Like before, the first argument may
  25207. Xbe a regular expression and the second may use the matches in the first.
  25208. X.sp
  25209. XFor each new list, the system puts the following default alias in its
  25210. X".aliases" file:
  25211. X.sp
  25212. X.ce
  25213. X^@.*:(.*)@(.*\\..*) \\1@\\2
  25214. X.sp
  25215. XThis removes source routing.
  25216. X.SH .IGNORED
  25217. XAs described before, the system's home directory as well as every list's
  25218. Xsubdirectory contains a ".ignored" file which is used to filter out messages
  25219. Xsent by certain users. The default file contains entries for server,
  25220. Xbin, and sys; you may wish to add an entry for every list alias that is
  25221. Xdefined on your system. A list's ".ignored" file also contains an
  25222. Xentry of its alias and full email address, as well as the server account's
  25223. Xfull email address.
  25224. X.PP
  25225. XEntries in this file may also be regular expressions as explained in the
  25226. Xprevious section. For example, to restrict requests (and postings)
  25227. Xto .com and .edu domain addresses, one may add:
  25228. X.sp
  25229. X.ce
  25230. X~<.*\\.com|.*\\.edu>
  25231. X.sp
  25232. XNotice, it is incorrect to list them as follows:
  25233. X.sp
  25234. X.ce
  25235. X~.*\\.com
  25236. X.ce
  25237. X~.*\\.edu
  25238. X.sp
  25239. Xas anything not from the .com domain matches the first regular expression,
  25240. Xand therefore will be ignored.
  25241. XTo refuse access to certain user names and certain sites one may include:
  25242. X.sp
  25243. X.ce
  25244. X \.*\\.bar\\.com|jdoe@.*
  25245. X.sp
  25246. XThe system's manager should use extra caution when adding regular expressions
  25247. Xto the system's ".ignored" file, because a simple '.*' prohibits anyone from
  25248. Xusing its services.
  25249. X.SH SEE\ ALSO
  25250. Xcatmail(1), listproc(1), server(1), serverd(1), start(1)
  25251. X.SH AUTHOR
  25252. X.nf
  25253. XAnastasios C. Kotsikonas
  25254. XCopyright (c) 1991-93, Anastasios Kotsikonas
  25255. XComments to tasos@cs.bu.edu
  25256. X.fi
  25257. *-*-END-of-doc/list.1-*-*
  25258. echo x - doc/listproc.1
  25259. sed 's/^X//' >doc/listproc.1 <<'*-*-END-of-doc/listproc.1-*-*'
  25260. X.\" ListProcessor System
  25261. X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
  25262. X.\"
  25263. X.TH listproc 1 "ListProcessor"
  25264. X.SH NAME
  25265. X\fBlistproc\fP \- process requests sent to the ListProcessor request handler
  25266. X.SH SYNOPSIS
  25267. X\fBlistproc\fP [\fB-1\fP] [\fB-e\fP] [\fB-i\fP] [\fB-n\fP] {[\fB-a\fP\ <\fBLIST_ALIAS\fP>]}* {[\fB-r\fP\ <\fBreq\fP>]}* {[\fB-d\fP\ <\fBreq\fP>]}* {[\fB-b\fP\ <\fBreq\fP>]}* [\fB-B\fP] [\fB-D\fP]
  25268. X.SH DESCRIPTION
  25269. X\fIlistproc\fP processes user requests sent to \fIlistproc@your-domain\fP,
  25270. Xforwards requests about known remote lists, and processes list-owner
  25271. Xadministrative requests (see also the LIST\ OWNERS section below).
  25272. XEach request should appear in a separate line with any possible arguments.
  25273. XThe file
  25274. X".ignored" is used in the system's home directory to filter out unwanted
  25275. Xsenders. If the system is not instructed to ignore invalid requests
  25276. X(see the CONFIG section in \fIserver(1)\fP), the sender is notified of the first
  25277. Xinvalid request; all subsequent requests are ignored.
  25278. XFor each successfully completed request,
  25279. Xa confirmation is sent back to the sender.
  25280. X.PP
  25281. X\fIlistproc\fP stops reading
  25282. Xrequests when it encounters the string "--" in a line by itself, which
  25283. Xon most systems signifies the start of the .signature message, or at the
  25284. Xfirst occurence of a thankful request. \fIlistproc\fP reads the \fIconfig\fP
  25285. Xfile (see \fIserver(1)\fP).
  25286. X.PP
  25287. XSubscriptions may be
  25288. Xmanager-approved (private lists), files and archive indices may be password
  25289. Xprotected (private archives), and requests may be placed in a batch queue.
  25290. XA single request may span multiple lines if each part ends with
  25291. X\fI&\\n\fP.
  25292. X.SH USER\ REQUESTS
  25293. XThe following user requests are recognized (requests may be abbreviated):
  25294. X.TP
  25295. X\fIhelp\fP\ [topic]
  25296. XSend a help message on all valid requests or the selected topic (possibly
  25297. Xa request) only.
  25298. X.TP
  25299. X\fIset\fP\ list\ [option arg(s)]
  25300. XWithout the optional arguments, return the current values for all options
  25301. Xset for \fIlist\fP; otherwise, 
  25302. Xset subscriber preferences for \fIlist\fP.
  25303. X.sp
  25304. X\fIoption\fP can be:
  25305. X.in +2
  25306. X.sp
  25307. X\fImail\fP: set mail preferences.
  25308. X.sp
  25309. X.in +2
  25310. X\fIarg\fP has to be one of the following:
  25311. X.sp
  25312. X.in +2
  25313. X\fIack\fP: send a copy of the current message to the original sender.
  25314. X.sp
  25315. X\fInoack\fP: do not send a copy of the current message to the original sender.
  25316. XThis is the default for newly subscribed users.
  25317. X.sp
  25318. X\fIpostpone\fP: do not send any messages to the particular subscriber until
  25319. Xhe changes status again.
  25320. X.sp
  25321. X\fIdigest\fP: do not send individual messages to the particular
  25322. Xsubscriber. Instead, store messages in a digest and send it when the
  25323. Xdigest exceeds a specified number of lines, or when a specified amount
  25324. Xof time has passed since the last digest was sent.
  25325. X.sp
  25326. XIf the mail mode is changed from \fIdigest\fP to anything else,
  25327. Xall messages currently stored for the next digest will be sent to the
  25328. Xsubscriber at once, in digest format.
  25329. X.in -2
  25330. X.in -2
  25331. X.sp
  25332. X\fIpassword\fP: change the password (used to establish
  25333. Xsubscriber privileges when connecting to ListProcessor for a "live" session and
  25334. Xfor the option below).
  25335. X.sp
  25336. X.in +2
  25337. X\fIargs\fP must be: old-password new-password.
  25338. X.in -2
  25339. X.sp
  25340. X\fIaddress\fP: set the address the user is subscribed with (if allowed for this
  25341. Xlist).
  25342. X.sp
  25343. X.in +2
  25344. X\fIargs\fP must be: current-password new-address.
  25345. X.sp
  25346. X.in -2
  25347. X\fIconceal\fP: set the user's visibility.
  25348. X.sp
  25349. X.in +2
  25350. X\fIarg\fP must be one of the following:
  25351. X.sp
  25352. X.in +2
  25353. X\fIyes\fP: the user is not listed in \fIrecipients\fP and \fIstatistics\fP
  25354. Xrequests.
  25355. X.sp
  25356. X\fIno\fP: the user's email address and name are made public.
  25357. X.in -2
  25358. X.in -2
  25359. X.in -2
  25360. X.TP
  25361. X\fIsubscribe\fP\ list\ full_name
  25362. XSubscribe the sender to \fIlist\fP (note, his email address is used for
  25363. Xsubscription, not his \fIfull_name\fP). A password is assigned by the
  25364. Xsystem at that time and is included in the reply message to the new
  25365. Xsubscriber. The password is to be used when connecting to the interactive
  25366. Xpart of the system for identification purposes, and for changing the
  25367. Xsubscription address if allowed for this list.
  25368. X.TP
  25369. X\fIwhich\fP
  25370. XGet a list of local mailing lists to which the sender has subscribed.
  25371. X.TP
  25372. X\fIunsubscribe\fP\ list
  25373. XRemove the sender from the specified \fIlist\fP.
  25374. X.TP
  25375. X\fIsignoff\fP\ list
  25376. XAlias of the unsubscribe request.
  25377. X.TP
  25378. X\fIrecipients\fP\ list
  25379. XGet a list of all subscribers of \fIlist\fP. The request is also forwarded
  25380. Xto all peer lists, and the servers handling them will respond accordingly.
  25381. XThe user is notified when this request is being forwarded. If a list
  25382. Xis private, only members may issue this request.
  25383. X.TP
  25384. X\fIreview\fP\ list
  25385. XAlias of the recipients request.
  25386. X.TP
  25387. X\fIinformation\fP\ list
  25388. XGet information about a particular \fIlist\fP.
  25389. X.TP
  25390. X\fIstatistics\fP\ list\ {[subscriber\ email\ address(es)]\ |\ [-all]}
  25391. XObtain a count of messages sent per subscriber to the specified \fIlist\fP,
  25392. Xor by those subscribers given as argument only (wild characters are
  25393. Xsupported). If \fI-all\fP is specified, then statistics are compiled for all
  25394. Xusers (currently subscribed or not) who have posted to the list in the past.
  25395. XThe request is also forwarded to all peer lists and the
  25396. Xservers handling them will respond accordingly.
  25397. XThe user is notified when this request is being forwarded.
  25398. XIf a list is private, only members may issue this request.
  25399. X.TP
  25400. X\fIrun\fP\ list\ [password\ cmd\ [args]]
  25401. XWithout the optional arguments, just list all commands that may be executed
  25402. Xby subscribers of this \fIlist\fP. Otherwise, run \fIcmd\fP with the
  25403. Xoptional \fIargs\fP, if the correct \fIpassword\fP is provided. The reply
  25404. Xwill contain the output from stdout and/or stderr.
  25405. X.TP
  25406. X\fIlists\fP
  25407. XObtain a list of mailing list addresses that are serviced by this system,
  25408. Xwith a small description of their purpose. If remote lists (see below)
  25409. Xare also defined, their addresses and descriptive messages will also be
  25410. Xincluded.
  25411. X.TP
  25412. X\fIindex\fP\ [archive\ |\ path-to-archive]\ [/password]\ [-all]
  25413. XObtain an index of files in the specified \fIarchive\fP (or the master archive
  25414. Xif none specified) and all of its subarchives if the the \fI-all\fP
  25415. Xoption is specified. Certain archives may be
  25416. Xprivate, and these require a \fI/password\fP to be able to obtain their
  25417. Xindices. Archives on different places in the hierarchy may have the same
  25418. Xnames and they can be distinguished by specifying paths to them; 
  25419. X\fIpath-to-archive\fP has the form \fIarchive[/archive[/archive...]]\fP.
  25420. X\fIindex\fP requests always report the paths to the archives they list.
  25421. X.TP
  25422. X\fIget\fP\ <archive\ |\ path-to-archive>\ file\ [/password]\ [parts]
  25423. XGet the specified \fIfile\fP from the \fIarchive\fP given. The file 
  25424. Xmay have been
  25425. Xsplit into smaller parts due to its size, in which case each part will
  25426. Xbe sent in a different email message. If only certain \fIparts\fP are desired,
  25427. Xthey may be given as arguments (numbers, separated by spaces -- ranges
  25428. Xare not recognized). Certain archives may be private, in which case their
  25429. X\fI/password\fP has to be provided in order to get the desired files.
  25430. XArchives on different places in the hierarchy may have the same
  25431. Xnames and they can be distinguished by specifying paths to them;
  25432. X\fIpath-to-archive\fP has the form \fIarchive[/archive[/archive...]]\fP.
  25433. XIf the file is pure binary, it will be uuencoded first.
  25434. X.TP
  25435. X\fIsearch\fP\ <archive\ |\ path-to-archive>\ [/password]\ [-all]\ <pattern>
  25436. XSearch all files in the specified archive (and all of its subarchives if
  25437. X\fI-all\fP) and return lines that match the \fIpattern\fP.
  25438. XThe pattern can be an extended regular expression with egrep(1)-style syntax,
  25439. Xwith support for the following additional operators: '~', if leading the
  25440. Xregular expression it reverses its meaning; '|' and '&' separate multiple
  25441. Xregular expressions (logical OR and AND); '<' '>' group regular expressions
  25442. X(we preserve the meaning of the parentheses from ed(1), and remove the
  25443. Xmeaning of < and > from ed(1) since in the ListProcessor context they are either
  25444. Xthe default, or inappropriate).
  25445. XThese can be used literally by escaping them
  25446. Xwith '\\'. In addition, the following characters should be defined
  25447. Xin matched pairs: (), <>, []. \fIpattern\fP may be enclosed in single
  25448. Xor double quotes. Pattern matching is case insensitive.
  25449. X.TP
  25450. X\fIfax\fP\ <fax-no>\ <archive\ |\ path-to-archive>\ file\ [/password]\ [parts]
  25451. XSame as the \fIget\fP request except that the files are faxed to the
  25452. Xspecified number.
  25453. X.TP
  25454. X\fIrelease\fP
  25455. XGet information about the current release of this server system.
  25456. X.TP
  25457. X\fIexecute\fP\ password\ #command\ [arguments]
  25458. XIntended for the system's \fImanager\fP, this will execute the  \fIcommand\fP
  25459. Xwith the optional \fIarguments\fP and send the output (if any) from stdout
  25460. Xand/or stderr to the sender. See the sample \fIconfig\fP file for
  25461. X\fIpassword\fP definition.
  25462. X.PP
  25463. XFor a list of the list administration requests that may be issued by list
  25464. Xowners, see the LIST\ OWNERS section below.
  25465. X.SH OPTIONS
  25466. XThe following command line options are recognized:
  25467. X.TP
  25468. X-1
  25469. XExecute only once; process any requests and return control to
  25470. X\fIserverd\fP(1); any new messages that may have arrived in the meantime will
  25471. Xbe processed at a later time. Without this option, \fIlistproc\fP will be
  25472. Xlistening for requests for ever. \fIserverd\fP(1)
  25473. Xuses this option by default when spawning \fIlisterv\fP.
  25474. X.TP
  25475. X-e
  25476. XEcho reports to the screen; it has no effect if the system has been compiled
  25477. Xwith -DSYSLOG.
  25478. X.TP
  25479. X-i
  25480. XGo to interactive mode -- messages by \fIlistproc\fP are not mailed out
  25481. Xbut instead \fIserverd\fP(1) reads them during its interactive session. Do not
  25482. Xuse this option in the \fIconfig\fP file (see \fIserver(1)\fP).
  25483. X.TP
  25484. X-n
  25485. XBy default, peer servers are notified upon \fIstatistics\fP and
  25486. X\fIrecipients\fP requests. The system uses a protocol for avoiding
  25487. Xloops as described in \fIserver\fP(1).
  25488. XIf you detect loops with other servers, you should use this option to
  25489. Xturn off notification of peer servers.
  25490. X.TP
  25491. X-a LIST_ALIAS
  25492. XUsually, subscriptions are automatic. This option turns off automatic
  25493. Xsubscription to the specified list (\fILIST_ALIAS\fP should be in capital
  25494. Xletters), and makes this list private (members only may issue \fIrecipients\fP
  25495. Xand \fIstatistics\fP requests). The sender is notified of this effect,
  25496. Xand a message is sent
  25497. Xto the list's owner requesting his/her approval, with instructions for
  25498. Xplacing the subscription. Notice that the specified list has to be defined
  25499. Xbeforehand via a \fIlist\fP directive in the \fIconfig\fP file. This
  25500. Xoption may be repeated any number of times.
  25501. X.TP
  25502. X-c LIST_ALIAS
  25503. XConceal \fILIST_ALIAS\fP from \fIlists\fP requests.
  25504. X.TP
  25505. X-r request
  25506. XPlace a restriction on the specified server \fIrequest\fP as outlined above.
  25507. XIf the number of users on the system at the time the request is about
  25508. Xto be processed is above the limit
  25509. Xgiven in the \fIconfig\fP file (using the \fIrestriction\fP directive),
  25510. Xthe request is rejected \-\- meant for requests that may take a 
  25511. Xconsiderable amount
  25512. Xof resources such as the \fIstatistics\fP request \-\- this option may
  25513. Xbe repeated any number of times. List administration requests are not
  25514. Xsubject to these restrictions (see later on).
  25515. X.TP
  25516. X-d request
  25517. XDisable \fIrequest\fP, i.e. make it totally unknown to the server \-\- this
  25518. Xsupersedes any \fIdisable\fP directives for this request in the \fIconfig\fP
  25519. Xfile, i.e. this request will not be recognized for any list (see
  25520. X\fIserver\fP(1)).
  25521. XHowever, help is still available for that request. List administration
  25522. Xrequests are also subject to these restrictions (see later on). This
  25523. Xoption may be repeated any number of times.
  25524. X.TP
  25525. X-b request
  25526. XAll such \fIrequest\fPs will be batch-processed if they arrive between
  25527. Xthe hours specified in the \fIconfig\fP file.
  25528. XThis option may be repeated any number of times.
  25529. X.TP
  25530. X-B
  25531. XProcess the batch queue. This is done automatically by \fIserverd\fP(1) after
  25532. Xmidnight every day, or when the system is restarted, so no further action
  25533. Xneeds to be taken. Caution:
  25534. Xdo not place this option in the definition of \fIserver\fP in the
  25535. X\fIconfig\fP file. If you do so, only the batch queue
  25536. Xwill be processed (no new requests will be processed, ever).
  25537. XThe batch queue is processed once a day only, unless the system
  25538. Xis restarted repeatedly.
  25539. X.TP
  25540. X-D
  25541. XTurns debugging on. When the \fIsystem\fP mailmethod is used, a
  25542. Xcopy of the last SMTP transaction can be found in the files
  25543. XHOMEDIR/sent and HOMEDIR/received.
  25544. X.SH PEER\ SERVERS
  25545. XThe system supports the notion of remote lists. A ListProcessor may know of
  25546. Xremote lists served by remote servers. Yet users may send requests about
  25547. Xthese remote lists to this server, which will in turn forward
  25548. Xthem to the remote servers. The user is notified when a list is not local
  25549. Xand his/her request is about to be forwarded.
  25550. XA \fIlists\fP request will tell the user which remote lists are known 
  25551. Xto this server.
  25552. X.PP
  25553. XRemote lists should be made known
  25554. Xto this server only if they are served by a server of version 5.31 or higher.
  25555. XThis restriction is posed because of incompatible requests
  25556. Xacross various list management systems. See the
  25557. Xdiscussion about the \fIconfig\fP file for setting up remote lists.
  25558. X.PP
  25559. XIn addition, \fIrecipients\fP and \fIstatistics\fP requests are
  25560. Xforwarded to the servers handling peer lists (the -n flag to \fIlistproc\fP
  25561. Xturns this feature off).
  25562. X.SH LIST\ OWNERS
  25563. XList owners are individuals responsible for list administration via
  25564. Xmail requests. Thus, list owners may be remotely located. Each list
  25565. Xhas to have at least one list owner. These owners may be different than
  25566. Xthe system's \fImanager\fP, and have special privileges: they may issue
  25567. Xrequests on users' behalf (add a user, remove a user, etc.) overriding
  25568. Xsystem restrictions set on regular users (these include disabled commands
  25569. Xas described above),
  25570. Xobtain reports about the lists they administer,
  25571. Xappend to the ".aliases" and ".ignored" files, change the welcoming
  25572. X(".welcome") and informative (".info") messages, as well as other system
  25573. Xfiles such as the aliases file (".aliases"), the ".ignored" file, the
  25574. Xsubscribers file (".subscribers"), the news file (".news") and the
  25575. Xpeers file (".peers"). In addition, they may moderate their lists and they
  25576. Xreceive various error messages pertaining to their lists.
  25577. XAll administrative requests are author authenticated and
  25578. Xpassword protected. Whenever a message cannot be author authenticated,
  25579. Xthe list's owner and \fImanager\fP are notified.
  25580. X.PP
  25581. XOn the other hand, list owners may not add restricted users; this
  25582. Xservice can be provided by contacting the system's \fImanager\fP.
  25583. X.PP
  25584. XList owners may also receive copies of user requests and/or error
  25585. Xmessages such as invalid postings, syntax errors on requests, etc.
  25586. XThese options are described in the following sections.
  25587. X.TP
  25588. XDefining list owners
  25589. XOnce a new mailing list is defined in the \fIconfig\fP file, the list's
  25590. Xowner address and access password are provided to the \fIlist\fP directive.
  25591. XOf course, this password should be made known to the owner; it
  25592. Xwill be needed for all administrative requests. Next, the owner's
  25593. Xaddress has to be registered in HOMEDIR/owners; the \fImanager\fP
  25594. Xsimply edits this file adding the owner's address along with the
  25595. Xlist's name (alias) he is assigned to, followed by any
  25596. Xpreferences (see below).
  25597. XMultiple owners for a list may be defined by adding their addresses to
  25598. Xthis file, and providing them with the list's password. However, only
  25599. Xthe primary owner's address (as defined by the \fIlist\fP directive) will
  25600. Xbe used as reference in correspondence and for system-error notifications,
  25601. Xand only the primary owner will be forwarded messages from his moderated list
  25602. Xfor approval.
  25603. XThe \fImanager\fP should also add his address (login name) to this file.
  25604. X.TP
  25605. XOwner preferences
  25606. XThe primary owner may wish to be copied on certain replies to user
  25607. Xrequests (such as subscribe), on error conditions (rejected
  25608. Xpostings, invalid requests, etc.), or on all cases. These preferences
  25609. Xare listed in the \fIowners\fP file on the line his address and list are
  25610. Xdefined. Valid preferences are:
  25611. X.sp
  25612. X.in +2
  25613. XCCSET: copy on \fIset\fP requests.
  25614. X.sp
  25615. XCCSUBSCRIBE: copy on \fIsubscribe\fP requests.
  25616. X.sp
  25617. XCCUNSUBSCRIBE: copy on \fIunsubscribe\fP requests.
  25618. X.sp
  25619. XCCRECIPIENTS: copy on \fIrecipients\fP requests.
  25620. X.sp
  25621. XCCINFORMATION: copy on \fIinformation\fP requests.
  25622. X.sp
  25623. XCCSTATISTICS: copy on \fIstatistics\fP requests.
  25624. X.sp
  25625. XCCRUN: copy on \fIrun\fP requests.
  25626. X.sp
  25627. XCCPRIVATE: copy on requests rejected because they are open only to
  25628. Xthe list's members.
  25629. X.sp
  25630. XCCERRORS: copy on various error conditions.
  25631. X.sp
  25632. XCCALL: all of the above.
  25633. X.in -2
  25634. X.sp
  25635. XOwner preferences are optional.
  25636. X.PP
  25637. XThe \fImanager\fP may define preferences
  25638. Xfor himself as well by using the keyword \fIserver\fP in place of a
  25639. Xlist alias. However, such preferences make sense only in the following
  25640. Xcases:
  25641. X.sp
  25642. X.in +2
  25643. XCCGET: copy on \fIget\fP requests.
  25644. X.sp
  25645. XCCINDEX: copy on \fIindex\fP requests.
  25646. X.sp
  25647. XCCLISTS: copy on \fIlists\fP requests.
  25648. X.sp
  25649. XCCRELEASE: copy on \fIrelease\fP requests.
  25650. X.sp
  25651. XCCHELP: copy on \fIhelp\fP requests.
  25652. X.sp
  25653. XCCERRORS: copy on various error conditions.
  25654. X.sp
  25655. XCCALL: all of the above.
  25656. X.in -2
  25657. X.sp
  25658. XManager preferences are optional.
  25659. X.TP
  25660. XOwner privileges
  25661. XWhenever an owner issues a user request on a user's behalf (see below),
  25662. Xall restrictions, including disabled commands, do not apply. All other
  25663. Xadministrative requests are subject to restrictions set by the \fImanager\fP.
  25664. XAll requests (user and administrative) are subject to batch-processing.
  25665. X.TP
  25666. XAdministrative requests
  25667. XThe following requests may be issued by a list's owner:
  25668. X.TP
  25669. X\fIsystem\fP\ list password\ user-address\ #user-request
  25670. XThis request overrides all system restrictions and executes
  25671. X\fIuser-request\fP on behalf of \fIuser-address\fP; this
  25672. Xaddress has to appear as listed in the ".subscribers" file, where applicable.
  25673. XThe most frequent use of the \fIsystem\fP request is to subscribe a user
  25674. Xto a private list. For example:
  25675. X.sp
  25676. X.in +2
  25677. Xsystem herc herc1 john@foo #subscribe herc Some Name
  25678. X.in -2
  25679. X.sp
  25680. XIf a \fIuser-request\fP refers to a list, this list has to be
  25681. X\fIlist\fP, so that a list's owner may not have privileges over another
  25682. Xlist's affairs. Note that all replies about \fIuser-request\fP are
  25683. Xforwarded to \fIuser-address\fP, not the owner; therefore, care has to
  25684. Xbe taken to avoid syntax errors. The \fIsystem\fP request is not subject
  25685. Xto restrictions, disabled requests, and private list subscription
  25686. Xverification (it is still subject to private list review as outlined 
  25687. Xabove, and batching). To remove a member from his list, the owner may issue the
  25688. Xfollowing request:
  25689. X.sp
  25690. X.in +2
  25691. Xsystem herc herc1 john@foo #unsubscribe herc
  25692. X.in -2
  25693. X.sp
  25694. XTo bypass restrictions and review his list, the owner may issue the
  25695. Xfollowing:
  25696. X.sp
  25697. X.in +2
  25698. Xsystem venus venus1 his-address #review venus
  25699. X.in -2
  25700. X.sp
  25701. XIn general, \fIuser-request\fP may be any of the recognized user requests
  25702. Xdescribed under \fIlistproc\fP. The pound sign is mandatory.
  25703. XThere is no help available to users for this request for security reasons.
  25704. X.TP
  25705. X\fIapprove\fP\ list\ password\ tag
  25706. XWhenever a new message arrives for a moderated list a copy is sent to the
  25707. Xlist's owner soliciting his approval -- proper instructions for approving
  25708. Xor discarding a message are included. This request
  25709. Xapproves the message identified by the \fItag\fP number for posting to
  25710. X\fIlist\fP. The tag number is
  25711. Xprovided to the list's owner by \fIlistproc\fP and is unique.
  25712. X.TP
  25713. X\fIdiscard\fP\ list\ password\ tag
  25714. XIn contrast to the above request, this discards the message identified
  25715. Xby \fItag\fP. Messages that are not approved or discarded remain in the
  25716. Xlist's \fImoderated\fP file (see \fIlist\fP(1)).
  25717. X.TP
  25718. X\fIreports\fP\ list\ password
  25719. XObtain all reports pertinent to \fIlist\fP; this will send two mail messages:
  25720. Xone with the current report (HOMEDIR/lists/ALIAS/.report.list), and
  25721. Xone with the previously archived ones (HOMEDIR/lists/ALIAS/.rep.list.acc);
  25722. Xsee the REPORTS section below. Once the ".rep.list.acc" file is sent,
  25723. Xit is shrunk in size, therefore the owner should make sure he keeps the
  25724. Xcopy he receives.
  25725. X.sp
  25726. XThis request has no effect if the system is using syslog(3) to generate
  25727. Xreports.
  25728. X.TP
  25729. X\fIedit\fP\ list\ password\ file
  25730. XObtain the specified \fIfile\fP for editing; candidate files are:
  25731. X.sp
  25732. X.in +2
  25733. X\fIaliases\fP: obtain the list's aliases file.
  25734. X.sp
  25735. X\fIignored\fP: obtain the list's list of unwelcome addresses.
  25736. X.sp
  25737. X\fIinfo\fP: obtain the list's informative message.
  25738. X.sp
  25739. X\fIsubscribers\fP: obtain the list's subscribers list.
  25740. X.sp
  25741. X\fIwelcome\fP: obtain the list's welcoming message.
  25742. X.sp
  25743. X\fInews\fP: obtain the list's list of newsgroup connections.
  25744. X.sp
  25745. X\fIpeers\fP: obtain the list's peers.
  25746. X.in -2
  25747. X.TP
  25748. X\fIput\fP\ list\ password\ keyword\ [args]
  25749. XThis enables the list's owner to append to the ".aliases" and ".ignored" files,
  25750. Xand replace his list's ".welcome", ".info", ".aliases", ".ignored",
  25751. X".subscribers", ".news" and ".peers" files, depending
  25752. Xon the \fIkeyword\fP. Valid \fIkeyword\fPs are:
  25753. X.in +2
  25754. X.sp
  25755. X\fIalias\fP: Add a user address alias to the list's and system's ".aliases"
  25756. Xfiles (see .ALIASES below). This requires the new address and the address
  25757. Xused for subscription as arguments:
  25758. X.sp
  25759. Xput <list> <password> alias <new-alias> <address-as-subscribed>
  25760. X.sp
  25761. XFor example:
  25762. X.sp
  25763. X.in +2
  25764. Xput venus venus1 alias foo!john john@foo
  25765. X.in -2
  25766. X.sp
  25767. X\fIignore\fP: Add a user address to the list's ".ignore" file only. Of
  25768. Xcourse this address has to be provided as argument:
  25769. X.sp
  25770. Xput <list> <password> ignore <address-as-subscribed-or-aliased>
  25771. X.sp
  25772. XFor example:
  25773. X.sp
  25774. X.in +2
  25775. X.nf
  25776. Xput ermis ermis1 ignore jack@foo
  25777. Xput ermis ermis1 ignore foo!jack
  25778. X.fi
  25779. X.in -2
  25780. X.sp
  25781. X.nf
  25782. X\fIwelcome\fP,
  25783. X\fIinfo\fP,
  25784. X\fIaliases\fP,
  25785. X\fIignored\fP,
  25786. X\fIsubscribers\fP,
  25787. X\fInews\fP,
  25788. X.fi
  25789. X\fIpeers\fP: Create a new system file.
  25790. X.sp
  25791. XFor example:
  25792. X.sp
  25793. X.in +2
  25794. X.nf
  25795. Xput <list> <password> subscribers
  25796. Xtasos ACK PASSWORD NO Tasos Kotsikonas
  25797. Xjohn NOACK PASS1 NO John Doe
  25798. X.fi
  25799. X.in -2
  25800. X.sp
  25801. XNo arguments are needed. The text that is to
  25802. Xgo to the corresponding file starts at the line following this request
  25803. Xand spans till the end of the mail message. Thus, no more requests can
  25804. Xbe made in the same mail message -- they are treated as regular text;
  25805. Xsignature lines also signify the end of text, provided they start with
  25806. X"--" in a single line.
  25807. X.in -2
  25808. X.sp
  25809. XA confirmation is sent to the owner once a \fIput\fP request is successfully
  25810. Xprocessed.
  25811. X.SH OWNERS
  25812. XThe format of the \fIowners\fP file is as follows:
  25813. X.sp
  25814. XOne entry per line; each entry is the full email address of a list's
  25815. Xowner, followed by the list alias he owns, followed by any optional
  25816. Xpreferences. If the keyword \fIserver\fP is specified in place of the
  25817. Xlist alias, then preferences are defined for the \fImanager\fP.
  25818. X.SH SEE\ ALSO
  25819. Xcatmail(1), farch(1), list(1), queue(1), server(1), serverd(1), start(1)
  25820. X.SH AUTHOR
  25821. X.nf
  25822. XAnastasios C. Kotsikonas
  25823. XCopyright (c) 1991-93, Anastasios Kotsikonas
  25824. XComments to tasos@cs.bu.edu
  25825. X.fi
  25826. *-*-END-of-doc/listproc.1-*-*
  25827. echo x - doc/queue.1
  25828. sed 's/^X//' >doc/queue.1 <<'*-*-END-of-doc/queue.1-*-*'
  25829. X.\" ListProcessor System
  25830. X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
  25831. X.\"
  25832. X.TH queue 1 "ListProcessor"
  25833. X.SH NAME
  25834. X\fBqueued\fP \- ListProcessor mail queue daemon
  25835. X.SH SYNOPSIS
  25836. X\fBqueued\fP <\fBfrequency\fP>
  25837. X.SH NAME
  25838. X\fBpqueue\fP \- process the specified mail queue files
  25839. X.SH SYNOPSIS
  25840. X\fBpqueue\fP [\fB-e\fP] [\fB-D\fP] <\fBfiles\fP>
  25841. X.SH OVERVIEW
  25842. XThis part of the ListProcessor system can be employed only when using the
  25843. X\fIsystem\fP mailmethod (see \fIserver\fP(1)).
  25844. XMessages and replies to requests not
  25845. Xdelivered due to network problems are queued by the system in the
  25846. Xdirectory HOMEDIR/mqueue. This part of the system attempts periodic
  25847. Xredelivery of these files. If problems still persist, files (messages)
  25848. Xthat cannot be delivered are requeued.
  25849. X.SH DESCRIPTION:\ queued
  25850. XThis is the daemon that looks for files in the mail queue. It uses
  25851. X\fIpqueue\fP for redelivery. The queue is checked every \fIfrequency\fP
  25852. Xseconds. Whenever an error occurs with \fIpqueue\fP, \fIqueued\fP sends
  25853. Xa mail message to \fImanager\fP (as defined in the \fIconfig\fP file)
  25854. Xand aborts.
  25855. X.PP
  25856. X\fIqueued\fP is not spawned by \fIstart\fP(1) in order to reduce the number of
  25857. Xprocesses running, since the probability of messages being queued is
  25858. Xvery low. Instead, it should be started manually whenever there are
  25859. Xfiles in the mail queue directory.
  25860. X.SH DESCRIPTION:\ pqueue
  25861. XThe \fIfiles\fP given as arguments are redelivered. If any of these
  25862. Xcannot be redelivered, they are requeued and will be processed in the next
  25863. Xrun. \fIpqueue\fP reports to the file HOMEDIR/.report.pqueue
  25864. X.PP
  25865. XThe following command line options are recognized:
  25866. X.TP
  25867. X-e
  25868. XEcho reports to the screen; it has no effect if the system has been compiled
  25869. Xwith -DSYSLOG.
  25870. X.TP
  25871. X-D
  25872. XTurns debugging on; a copy of the last SMTP transaction can be found in 
  25873. Xthe files HOMEDIR/sent and HOMEDIR/received. Warning: these files
  25874. Xare also used by \fIlist\fP(1) and \fIlistproc\fP(1) when they have their
  25875. Xdebug mode on, so use caution.
  25876. X.SH NOTE
  25877. XThis mail queueing system should not be confused with the one implemented
  25878. Xby sendmail(1).
  25879. X.SH SEE\ ALSO
  25880. Xserver(1)
  25881. X.SH AUTHOR
  25882. X.nf
  25883. XAnastasios C. Kotsikonas
  25884. XCopyright (c) 1991-93, Anastasios Kotsikonas
  25885. XComments to tasos@cs.bu.edu
  25886. X.fi
  25887. *-*-END-of-doc/queue.1-*-*
  25888. echo x - doc/server.1
  25889. sed 's/^X//' >doc/server.1 <<'*-*-END-of-doc/server.1-*-*'
  25890. X.\" ListProcessor System
  25891. X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
  25892. X.\"
  25893. X.TH server 1 "ListProcessor"
  25894. X.SH NAME
  25895. XListProcessor version 6.0
  25896. X.SH OVERVIEW
  25897. XThis is a system that implements various mailing lists with one
  25898. Xlist manager. It is automated, and obliterates the need for user intervention
  25899. Xand maintenance of multiple aliases of the form "list, list-owner,
  25900. Xlist-request", etc. There is support provided for public and private 
  25901. Xhierarchical archives,
  25902. Xmoderated and non-moderated lists, peer lists, peer servers, private
  25903. Xlists, address aliasing, news connections and gateways, mail queueing,
  25904. Xdigests, list ownership, owner preferences, crash recovery, batch
  25905. Xprocessing, configurable headers, regular expressions, archive searching,
  25906. Xand live user connections via TCP/IP.
  25907. X.SH OBTAINING\ INFORMATION
  25908. X.TP
  25909. Xmailing lists, aliases, news groups, peer lists
  25910. XSee list(1).
  25911. X.TP
  25912. Xuser requests, list owners, peer servers, remote lists
  25913. XSee listproc(1).
  25914. X.TP
  25915. Xdistributing incoming mail
  25916. XSee catmail(1).
  25917. X.TP
  25918. Xarchiving files
  25919. XSee farch(1).
  25920. X.TP
  25921. Xarchiving of lists' messages
  25922. XSee below.
  25923. X.TP
  25924. Xprocessing the mail queue
  25925. XSee queue(1).
  25926. X.TP
  25927. Xoptions for the system's daemon
  25928. XSee serverd(1).
  25929. X.TP
  25930. Xstarting and stopping the system
  25931. XSee start(1).
  25932. X.TP
  25933. Xlive connections
  25934. XSee ilp(1) and serverd(1).
  25935. X.SH SYSTEM\ SETUP
  25936. XThe ListProcessor system is installed under the HOMEDIR directory as defined
  25937. Xin src/Makefile; HOMEDIR points to the top level directory of the installation;
  25938. Xa \fIserver\fP user account has to be setup. The system should be installed and
  25939. Xset up using this account, and always be started from this account as well
  25940. X(see \fIstart\fP(1)).
  25941. XThen, the following alias
  25942. Xhas to be defined in /etc/aliases, /usr/lib/aliases or /usr/ucblib/aliases
  25943. X(depending
  25944. Xon your system) for listprocessor (where users send their requests):
  25945. X.sp
  25946. X.in +2
  25947. Xlistproc: "|HOMEDIR/catmail -r -f"
  25948. X.in -2
  25949. X.PP
  25950. XVarious mailing lists are set up in a similar fashion; see \fIlist\fP(1).
  25951. X.PP
  25952. XIt is important to keep in mind that mailers should convert any text lines 
  25953. X(not header lines) of incoming messages starting with "From ", to ">From ".
  25954. XThis is automatically done by the -f flag to \fIcatmail\fP(1).
  25955. X.PP
  25956. XThe \fIcatmail\fP(1) utility is used to append incoming mail to the appropriate
  25957. Xfiles. When properly set up, it has the setuid bit turned on. Since
  25958. Xexecute permission is granted to everybody, it is possible for anyone
  25959. Xto append to these files; however, each time \fIcatmail\fP(1) is run, it
  25960. Xreports the user id and user name whom access was granted to.
  25961. X.PP
  25962. XIf the system is to go interactive (see \fIserverd\fP(1)), you have to add
  25963. Xthe following line in your /etc/services file:
  25964. X.sp
  25965. X.ce
  25966. Xulistproc   372/tcp
  25967. X.sp
  25968. XSee also src/Makefile.
  25969. X.PP
  25970. XHow the system operates is defined in the \fIconfig\fP file (see below).
  25971. XOnce the system is loaded, you will have to run the script \fIsetup\fP;
  25972. Xthis will ensure that all necessary files and directories are present, and
  25973. Xhave the right permissions. Before starting the
  25974. Xsystem, you may wish to edit the ".ignored" file in HOMEDIR (see \fIlist\fP(1)).
  25975. XAt this point, you may also wish to alter the help files in HOMEDIR/help;
  25976. Xeach file in that directory corresponds to one of the recognized requests.
  25977. XHelp files may be simple text files, or shell scripts starting with "#!"
  25978. Xin the first line, followed by the shell to execute.
  25979. X.PP
  25980. XFile protections are a major issue and the requirements may vary from system
  25981. Xto system. The problems usually arise from inadequate write permissions while
  25982. Xappending mail to the various mail files. The system uses the environment
  25983. Xvariable ULISTPROC_UMASK in the same way as umask(1) is used when updating
  25984. Xfiles. If not set, the default is 066. A value of 026 should be acceptable in
  25985. Xmost cases. This variable should be set in both .cshrc and .profile. For
  25986. Xarchived files, you may use the ULISTPROC_ARCHIVES_UMASK variable, which 
  25987. Xdefaults to the value set for ULISTPROC_UMASK.
  25988. X.PP
  25989. XFinally, experiment with the various mail methods described below, until
  25990. Xyou get the proper "From " line in the beginning of the outgoing message;
  25991. Xfor instance, when \fIlistproc\fP(1) is replying to a request, you should see
  25992. Xsomething like "From listproc@your-domain" as the first line of the header;
  25993. Xor when
  25994. Xthe list abc is distributing messages, this line should look like
  25995. X"From abc@your-domain". If you cannot get it to work, i.e. you get something
  25996. Xlike "From server@your-domain" then the server system may have
  25997. Xto run with superuser privileges. In this case, the server userid should
  25998. Xbe the same as root's. Also consult the PORT\ SPECIFIC section below,
  25999. Xfor suggested mailmethods. You will not have any of these problems
  26000. Xif you use the \fIsystem\fP mailmethod (see below).
  26001. X.PP
  26002. XIf this part of the setup is not done properly, peer lists will not
  26003. Xwork at all and users may not be able to reply to the list. As a final
  26004. Xnote, if \fItelnet\fP does not seem to be sending any mail, it is a
  26005. Xbug with the telnet implementation on your system: telnet
  26006. Xcannot have its input redirected or piped, and should be reported to your
  26007. Xvendor.
  26008. X.PP
  26009. XThe last step for a complete set up is to define your system in the
  26010. X\fIconfig\fP file.
  26011. X.SH CONFIG
  26012. XThe server system is defined in the \fIconfig\fP file; an example
  26013. Xfile is provided with the system. This file is used by \fIstart\fP(1),
  26014. X\fIserverd\fP(1), \fIlist\fP(1) and \fIlistproc\fP(1), and is not a shell
  26015. Xscript.
  26016. X.PP
  26017. XThe following keywords (directives) are recognized and is advisable that each
  26018. Xone of them starts at column 1; directives may span multiple lines if each
  26019. Xline is terminated by &\\n:
  26020. X.TP
  26021. X\fIorganization\fP name
  26022. XThis defines your organization when posting to news and upon connection
  26023. Xestablishment of a live session. \fIname\fP may
  26024. Xinclude blanks.
  26025. X.TP
  26026. X\fIserver\ listproc\fP@your-domain\ command-line-options
  26027. XThis defines the list processor; the first argument is the full email address
  26028. Xof the server (e.g. listproc@foo.edu) followed by any command line
  26029. Xoptions to be used when \fIserverd\fP spawns \fIlistproc\fP
  26030. X(see \fIserverd\fP(1), \fIlistproc\fP(1)).
  26031. X.TP
  26032. X\fIlist\fP\ list_alias\ email-addr\ owner-addr\ password\ cmd-line-opt
  26033. XThis defines a mailing list; the first argument is the list's alias
  26034. Xin /etc/aliases, /usr/lib/aliases or /usr/ucblib/aliases (see \fIlist\fP(1)),
  26035. Xfollowed by its full email
  26036. Xaddress, followed by its owner's full email address, followed by the
  26037. Xlist's password for maintenance, followed by any command line options
  26038. Xto be used when \fIserverd\fP(1) spawns \fIlist\fP(1).
  26039. X.TP
  26040. X\fIheader\fP\ list\ {\ [Header-Line:]\ ...\ }
  26041. XIt specifies precious header lines from the original sender's message
  26042. Xthat are to be preserved during distribution. The \fIlist\fP has to be
  26043. Xdefined before, and precious header lines are specified within the
  26044. Xenclosing \fI{\fP and \fI}\fP, possibly spanning multiple lines.
  26045. X.TP
  26046. X\fIdefault\fP\ list\ {\ [option = value]\ ...\ }
  26047. XDetermine various default values for \fIlist\fP for new and current subscribers;
  26048. Xthe list has to be defined before. Pairs of options and values may be repeated
  26049. Xany number of times, and may span multiple lines; if certain options are
  26050. Xmissing, then system defaults are used. Valid \fIoption\fPs are:
  26051. X.sp
  26052. X.in +2
  26053. X\fIaddress\fP: turn user-settable subscription addresses on or off. Valid values
  26054. Xare:
  26055. X.sp
  26056. X.in +2
  26057. X\fIfixed\fP: users are not allowed to change the address they are subscribed
  26058. Xwith via the \fIset <list> address\fP request (see \fIlistproc\fP(1)).
  26059. XThis is the system default as well.
  26060. X.sp
  26061. X\fIvariable\fP: opposite of the above.
  26062. X.in -2
  26063. X.sp
  26064. X\fImail\fP: select the default mail mode for new subscribers. Valid values are:
  26065. X.sp
  26066. X.in +2
  26067. X\fIack\fP: see \fIset\fP in \fIlistproc\fP(1).
  26068. X.sp
  26069. X\fInoack\fP: see \fIset\fP in \fIlistproc\fP(1); this is the system default.
  26070. X.sp
  26071. X\fIpostpone\fP: see \fIset\fP in \fIlistproc\fP(1) (a rather useless setting indeed).
  26072. X.sp
  26073. X\fIdigest\fP: see \fIset\fP in \fIlistproc\fP(1).
  26074. X.in -2
  26075. X.sp
  26076. X\fIpassword\fP: define a single password for new users; if missing, the system
  26077. Xassigns a random password. Any string that contains no white spaces may be
  26078. Xused.
  26079. X.sp
  26080. X\fIconceal\fP: determine the default visibility of new users; see \fIset\fP
  26081. Xin \fIlistproc\fP(1). Valid options are:
  26082. X.sp
  26083. X.in +2
  26084. X\fIyes\fP: hidden from \fIrecipients\fP and \fIstatistics\fP requests.
  26085. X.sp
  26086. X\fIno\fP: this is the system default.
  26087. X.in -2
  26088. X.in -2
  26089. X.TP
  26090. X\fIceiling\fP\ list\ max_messages
  26091. XRestrict the number of messages processed daily for \fIlist\fP to
  26092. X\fImax_messages\fP; this includes posted and rejected messages.
  26093. X.TP
  26094. X\fIremote\fP\ alias\ email-addr\ listproc-addr\ [host\ [port]]\ #Comment
  26095. XThis makes a remote list known to the server. A remote list is another
  26096. Xmailing list served by another server, and your server is now capable
  26097. Xof forwarding to the proper remote list processor any requests sent about
  26098. Xthis remote list to your server. \fIalias\fP is the name by which the remote
  26099. Xlist is known by, \fIemail-addr\fP is the full email address of the
  26100. Xremote list, \fIlistproc-addr\fP is the full email address of the
  26101. Xremote list processor, and \fI#Comment\fP
  26102. Xwill be used upon a \fIlists\fP request made to this server (the pound
  26103. Xsign is mandatory). \fIhost\fP is either the DNS name or IP address
  26104. Xof the remote server, used to connect to that server when a live request
  26105. Xrefers to that list; the \fIport\fP should be specified if not the default
  26106. X(372) (see \fIserverd\fP(1)).
  26107. X.sp
  26108. XRemote lists may have the same \fIalias\fP and they should not be confused
  26109. Xwith peer lists. However, each remote list should be defined only once.
  26110. XSee the discussion about PEER\ SERVERS (\fIlistproc\fP(1)) for further information.
  26111. X.TP
  26112. X\fIfax\fP fax-program options
  26113. XDefine the fax program to use for \fIfax\fP requests (if any) and any
  26114. Xcommand line options the program may use. The program should also be capable
  26115. Xof accepting the file to fax from its standard input; otherwise a script
  26116. Xwill have to be used instead which will in turn use the fax program
  26117. Xappropriately. If this directive is left or commented out, then \fIfax\fP
  26118. Xrequests are automatically turned off.
  26119. X.sp
  26120. XThe actual faxing program is called as follows:
  26121. X.sp
  26122. X.ce
  26123. X\fIfax-program\fP \fIoptions\fP fax-number < file
  26124. X.sp
  26125. XThis request may not be issued from a live session, since fax programs work
  26126. Xon email messages and extract the sender's address for reference when sending
  26127. Xthe cover page of the fax.
  26128. X.TP
  26129. X\fIunix_cmd\fP\ list_alias\ password\ name\ \'unix-command\ [args]\'\ #Comment
  26130. XAllow a \fIlist_alias\fP's subscribers only to execute the above
  26131. X\fIunix-command\fP aliased to \fIname\fP. The \fIpassword\fP is made known
  26132. Xto users who are to be given this privilege. The oprional \fIargs\fP may be
  26133. Xliteral arguments to the command as well as the special sequences \fI$n\fP,
  26134. Xwhere \fIn\fP is a digit from 1 to 9, or *; their meaning is that of the Bourne
  26135. Xshell, and they will be substituted by the user's actual arguments. For
  26136. Xexample:
  26137. X.sp
  26138. X.ce
  26139. Xunix_cmd ermis pass1 swap \'/bin/echo $2 $1\' #Syntax: swap <arg1> <arg2>
  26140. X.sp
  26141. Xwill swap the user's first and second arguments. The user would submit a
  26142. Xrequest that could look like this:
  26143. X.sp
  26144. X.ce
  26145. Xrun ermis pass1 swap arg1 arg2
  26146. X.sp
  26147. XNo security checks are made except to ensure that the arguments contain no `, |,
  26148. X:, < and >, so the \fImanager\fP is encouraged to review
  26149. Xand verify the proper functioning of \fIunix-command\fP. The \fIComment\fP
  26150. Xis used when users issue \'run <list>\' query requests.
  26151. X.TP
  26152. X\fIserverd\fP\ command-line-options
  26153. XThis defines the command line options that \fIstart\fP(1) is to use
  26154. Xwhen spawning \fIserverd\fP(1).
  26155. X.TP
  26156. X\fIrestriction\fP\ nusers
  26157. XIf a restriction is placed on a ListProcessor request (via a -r command line
  26158. Xoption to \fIlistproc\fP(1)), this directive defines the threshold number of users,
  26159. Xabove which the restriction will take effect.
  26160. X.TP
  26161. X\fIdisable\fP\ list_alias request
  26162. XThe specified server \fIrequest\fP is disabled for the specified list, and
  26163. Xall such requests for this list are rejected, except when issued by privileged
  26164. Xusers (list owners). The \fIlist_alias\fP has to
  26165. Xbe defined (via a \fIlist\fP directive) before any requests can
  26166. Xbe disabled.
  26167. X.TP
  26168. X\fImanager\fP\ full-email-address
  26169. XThis defines the recipient of all system error messages, and the system's
  26170. Xadministrator and caretaker; \fIfull-email-address\fP
  26171. Xcan be any valid user name that can be reached via email by your system.
  26172. XThe \fImanager\fP is usually the person responsible for the server
  26173. Xaccount.
  26174. X.TP
  26175. X\fIcomment server\fP\ #Actual comment
  26176. X.TP
  26177. X\fIcomment\fP\ list_alias\ #Actual comment
  26178. XA 'X-Comment:' line is included in every outgoing list/server message, and the
  26179. Xtext following the pound sign will be copied every time; note that the pound
  26180. Xsign is mandatory for the definition but will not be part of the actual string.
  26181. XA list's comment is also used for the \fIlists\fP request to
  26182. Xspecify the purpose of the particular mailing list. No 'X-Comment:' line
  26183. Xis included if this directive is not defined for the particular list and/or
  26184. Xserver.
  26185. X.TP
  26186. X\fIdigest\fP\ list_alias\ lines\ hours
  26187. XIf any subscriber to the list requests digests, a digest will be sent when
  26188. Xits length exceeds \fIlines\fP, or when \fIhours\fP have passed
  26189. Xwithout a digest being sent. Digests for a list are collected only if at
  26190. Xleast one of its subscribers has set his mail mode to \fIdigest\fP.
  26191. X.TP
  26192. X\fIarchive\fP\ list_alias\ dir\ filename\ [archive]\ [password]\ [digest]
  26193. XRequest that all public messages are automatically archived; \fIlist_alias\fP
  26194. Xis the list's name, \fIdir\fP is the directory that the archived
  26195. Xfiles will be located (a full path has to be specified, and the directory
  26196. Xhas to be writable by the server uid), \fIarchive\fP is the archive's name
  26197. Xand is a relative path under the default archive (listproc) or "-" for the
  26198. Xdefault, \fIpassword\fP is an optional password ("-" if none) to be used
  26199. Xif the archive is meant to be private, and the optional
  26200. Xkeyword \fIdigest\fP will force only digests to be archived; \fIfilename\fP
  26201. Xspecifies the format of the archived files, and may contain any lower case
  26202. Xcharacters and numbers, as well as the following special sequences:
  26203. X.in +2
  26204. X.sp
  26205. X%m: Numeric month (01 - 12)
  26206. X.sp
  26207. X%d: Numeric day of the month (01 - 31)
  26208. X.sp
  26209. X%y: Year (00 - 99)
  26210. X.sp
  26211. X%j: Julian date (001 - 366)
  26212. X.sp
  26213. X%h: Month name (Jan - Dec)
  26214. X.sp
  26215. X%a: Contents of the Archive-Name: header line, if present; cannot be used if
  26216. Xarchiving digests. The Archive-Name: header line has to be manually inserted
  26217. Xby the sender of the message; it may show up in the body of the message as
  26218. Xwell.
  26219. X.sp
  26220. X%#: Digest number; can only be used if archiving digests.
  26221. X.sp
  26222. X%1: First word of the first non-blank line of the message.
  26223. X.sp
  26224. X%v: Volume number, if the message contains a 'Volume # Number #' line before
  26225. Xthe actual message.
  26226. X.sp
  26227. X%n: Issue number, if the message contains a 'Volume # Number #' line before the
  26228. Xactual message.
  26229. X.sp
  26230. X%%: The character %
  26231. X.in -2
  26232. X.sp
  26233. XFor example, to archive messages daily:
  26234. X.sp
  26235. X.ce
  26236. Xarchive ermis HOMEDIR/archives/lists/ermis %y%m%d listproc/lists/ermis
  26237. X.sp
  26238. Xor to archive only files sent to the list:
  26239. X.sp
  26240. X.ce
  26241. Xarchive venus /ftp/lists/venus vol-%v.num-%n listproc/lists/venus johny-be-good
  26242. X.sp
  26243. Xand in this case the sender that wants a file to be archived would precede
  26244. Xit with a line similar to:
  26245. X.sp
  26246. X.nf
  26247. XVolume 10 Number 5
  26248. X.fi
  26249. X.sp
  26250. Xfollowed by the actual file.
  26251. X.sp
  26252. XWhen a new archive file is created, the Subject: line is used as the short
  26253. Xdescriptive message for the archive.
  26254. X.TP
  26255. X\fIfrequency\fP\ seconds
  26256. XHow often should \fIserverd\fP(1) check for new mail. When \fIseconds\fP is
  26257. Xset to zero, \fIserverd\fP does not sleep.
  26258. X.TP
  26259. X\fIbatch\fP\ start\ stop
  26260. XSpecify the hours (in military time) when requests are to be batched.
  26261. XThe defaults are 8 and 20. \fIstart\fP and \fIstop\fP should be within
  26262. Xthe same day (e.g. 8 am and 1 am the following day are not valid).
  26263. X.TP
  26264. X\fIlimit\fP\ keyword\ arguments
  26265. XUsed to set certain limits in the system; \fIkeyword\fP can be:
  26266. X.in +2
  26267. X.sp
  26268. X\fImessage\fP: limit the size of distributed messages to a certain
  26269. Xnumber of bytes, which is the \fIargument\fP following this keyword.
  26270. XA notification is sent back to the sender when this limit is exceeded,
  26271. Xincluding the first few lines of his/her original message for reference.
  26272. X.in -2
  26273. X.sp
  26274. X.in +2
  26275. X\fIfiles\fP: limit the size of archive files that can be sent out to a certain
  26276. Xnumber of bytes, which is the \fIargument\fP following this keyword.
  26277. XWhen this limit is reached, the file is automatically split into subparts.
  26278. X.TP
  26279. X\fIprecedence\fP\ string
  26280. XThe header of each outgoing message contains a Precedence: line; \fIstring\fP
  26281. Xcan be:
  26282. X.in +2
  26283. X.sp
  26284. Xbulk, junk, first-class, none: primarily used for vacation programs.
  26285. X.in -2
  26286. X.TP
  26287. X\fIoption\fP\ keyword
  26288. XThis defines a series of system-dependent options; \fIkeyword\fP can be:
  26289. X.in +2
  26290. X.sp
  26291. X\fIsysv_ps\fP: the system will assume a System V version of ps(1).
  26292. X.sp
  26293. X\fIbsd_ps\fP: the system will assume a BSD version of ps(1).
  26294. X.sp
  26295. X\fIbsd_mail\fP: define it if BSD (UCB) mail is available on your system; if this
  26296. Xis the case, make sure that /usr/ucb/mail is the path (or a link) to it; also
  26297. Xsee src/Makefile.
  26298. XThis is used to notify the \fImanager\fP of any error conditions.
  26299. X.sp
  26300. X\fIbad_telnet\fP: if the mail method used (see below) is \fItelnet\fP and 
  26301. Xthe system seems to send out only one message and then go to sleep, use
  26302. Xthis option.
  26303. X.sp
  26304. X\fIpost_mail\fP: this will force the system to post messages to news
  26305. Xgroups (using \fIinews\fP), using the groups' names (e.g. misc.test). Make
  26306. Xsure that \fIinews\fP resides in /usr/lib/news, or 
  26307. X/usr/lib/news/inews is a link to it (also see src/Makefile).
  26308. X.sp
  26309. X\fIgate_mail\fP: this will force the system to gate messages to news, using
  26310. Xthe gateways' email addresses.
  26311. X.sp
  26312. X\fIignore_invalid_requests\fP: ignore all unrecognized user requests and
  26313. Xprocess valid ones only; by default, the system aborts processing requests
  26314. Xupon the first invalid one, in which case a reply is sent to the user and
  26315. Xall subsequent requests are flushed.
  26316. X.sp
  26317. X\fIrelaxed_syntax\fP: by default, the system complains when a request is
  26318. Xgiven more arguments than expected. This turns such checking off.
  26319. X.in -2
  26320. X.TP
  26321. X\fImailmethod\fP\ method\ [arguments]
  26322. XEvery outgoing
  26323. Xmessage should begin with a line of the form:
  26324. X.in +2
  26325. X.sp
  26326. XFrom listproc@your-domain
  26327. X.sp
  26328. Xor
  26329. X.sp
  26330. XFrom list_alias@your-domain
  26331. X.sp
  26332. X.in -2
  26333. Xwhich depends on the mail \fImethod\fP used:
  26334. X.in +2
  26335. X.sp
  26336. X\fIsystem\fP: the recommended method; it provides a unified approach to
  26337. Xsending mail and it has been ported and tested on lots of systems (see
  26338. Xthe section PORT\ SPECIFIC below).
  26339. XIn addition, since a full set of the SMTP protocol is implemented,
  26340. X\fImanager\fP and list owners will be notified of invalid addresses and
  26341. Xvarious system problems.
  26342. XMoreover, mail will be queued when it cannot be delivered, in the
  26343. Xdirectory HOMEDIR/mqueue; see \fIqueue(1)\fP for more information
  26344. Xon how to process the mail queue.
  26345. X.sp
  26346. XThis method requires host TCP/IP and internet support; consult the
  26347. Xsrc/README file for more information.
  26348. X.sp
  26349. X\fItelnet\fP: to be used only when \fIsystem\fP is inappropriate and telnet(1)
  26350. Xis available on your host.
  26351. X.sp
  26352. X\fIenv_var\fP: usually followed by \fILOGNAME /bin/rmail\fP,
  26353. Xor \fILOGNAME /usr/lib/sendmail -ba\fP (-ba is mandatory) -- to be 
  26354. Xused only when the previous methods are inappropriate.
  26355. X.in -2
  26356. X.SH MAIL\ LOOPS
  26357. XThe system uses the following protocol for avoiding mail loops between
  26358. Xa list and news connections: In the header of the outgoing message an
  26359. X"Originator: " field is added. For each list plus listproc, a log of
  26360. Xthe most recent (500) Message-Id's is kept.
  26361. XWhenever a message is received, the
  26362. XOriginator, Reply-To and Message-Id fields are extracted and looked up in
  26363. Xthe ".ignored" and ".message.ids"
  26364. Xfiles in the list's subdirectory. Gateways that feed back to the list
  26365. Xshould preserve at least the Reply-To and Message-Id fields. The Originator
  26366. Xand Message-Id fields are preserved by this system. A new Reply-To is
  26367. Xtacked on when redistributing mail locally from a peer or a news feed.
  26368. X.PP
  26369. XTo avoid mail loops when forwarding ListProcessor requests to peers, the system
  26370. Xlooks up the Message-Id field in the ".message.ids" file in 
  26371. XHOMEDIR.
  26372. XIf this field is not preserved by the peer ListProcessor, it is suggested that you
  26373. Xturn off request forwarding when connecting with peers served by such
  26374. Xsystems, until a unified approach is taken. The Message-Id field is preserved
  26375. Xby this ListProcessor. This system is also using a special Subject field,
  26376. Xtotally proprietary and non-standard, in order to avoid unnecessary
  26377. Xforwarding of requests, thus cutting down on email traffic.
  26378. X.PP
  26379. XIn addition, the system searches incoming messages for Message-Ids in the
  26380. Xmessage body, as well as the occurence of the X-Listprocessor-Version header
  26381. Xline in it, since most bounced messages include the entire original message.
  26382. X.PP
  26383. XFinally, a checksum for each incoming message is obtained and looked up 
  26384. Xagainst a database of the 500 most recent sums in the file ".sums" in the
  26385. Xlist's subdirectory.
  26386. X.SH CRASH\ RECOVERY
  26387. XIt is possible that a message delivery was interrupted by a user
  26388. X(\fIstart -k\fP), or by the system (crash/reboot). A built-in mechanism
  26389. Xguarrantees to pick up delivery again from where it left off, if the
  26390. Xsystem is restarted using \fIstart\fP(1). Both \fIstart\fP(1) and \fIlist\fP(1)
  26391. Xreport to the effect that mail delivery was interrupted and will
  26392. Xresume. On the other hand, processing of interrupted requests will not
  26393. Xresume and all unprocessed requests will be lost.
  26394. X.SH COMMUNICATING
  26395. XUsers send requests to \fIlistproc@your-domain\fP and public messages to the
  26396. Xvarious \fIlist_alias@your-domain\fP.
  26397. X.SH ARCHIVES
  26398. XThe server has an archiving capability of files. Archives may be public
  26399. Xso that anyone can get files from them, or private so that only privileged
  26400. Xusers may obtain files from them. There is a master archive
  26401. Xin HOMEDIR/archives/listproc where all subarchives are defined. The archives
  26402. Xkeep lists of files that are available to users via a \fIget\fP request, and
  26403. Xindex of subarchives that are available to users via an \fIindex\fP
  26404. Xrequest.
  26405. X.PP
  26406. XAs outlined in \fIlist\fP(1), each list's public messages are
  26407. Xautomatically saved under the list's subdirectory in the file \fIarchive\fP.
  26408. XThis file may periodically be placed in the system's archives by hand (if not
  26409. Xarchiving automatically via the \fIarchive\fP directive), or may point to
  26410. X/dev/null. The archived files may not necessarily reside in
  26411. Xthe archive directories, as long
  26412. Xas the archives know where they are located. See the man page for
  26413. X\fIfarch(1)\fP for more information.
  26414. X.PP
  26415. XAlternatively, messages may be automatically archived via the \fIarchive\fP
  26416. Xdirective in the \fIconfig\fP file.
  26417. X.SH HELP
  26418. XThe system comes configured with default help topics the recognized
  26419. Xrequests. More topics may be added by editing the file
  26420. XHOMEDIR/help/TOPICS, adding the topic(s) and the file(s) where the
  26421. Xactual text exists.
  26422. X.PP
  26423. XHelp files may be simple text files or shell scripts, in which case they
  26424. Xhave to start with "#!" in the first line and be followed by the path
  26425. Xto the shell to be used; for example: #!/bin/sh
  26426. X.SH SYSTEM\ MAINTENANCE
  26427. XAs mentioned below, all programs report to certain files. The system's
  26428. Xmanager should periodically check the files HOMEDIR/.report.server
  26429. Xand the various HOMEDIR/lists/*/.report.list for any problems.
  26430. XAll messages sent are saved under HOMEDIR/mbox and 
  26431. XHOMEDIR/lists/*/mbox and they should be cleaned up periodically.
  26432. XFor debugging purposes, various warnings are written to 
  26433. XHOMEDIR/.warning; this file, as well as HOMEDIR/.report.catmail
  26434. Xare shrunk every time \fIstart\fP(1) is run.
  26435. X.PP
  26436. XFor whenever the necessity arises to administer the system remotely, the
  26437. Xfollowing scheme may be used to start or kill the system, process the mail
  26438. Xqueue, force an application to execute immediately, etc: a mail message
  26439. Xis sent to an alias whose sole role is to fire up an application; the
  26440. Xapplication has to have been setuid before.
  26441. X.PP
  26442. XFor instance, to start the
  26443. Xsystem remotely, you may set up an alias such as:
  26444. X.sp
  26445. X.nf
  26446. X.in +2
  26447. Xstart-server: "|HOMEDIR/start -cr > /dev/null"
  26448. X.in -2
  26449. X.fi
  26450. X.sp
  26451. XTo kill the system, you may define another alias:
  26452. X.sp
  26453. X.nf
  26454. X.in +2
  26455. Xkill-server: "|HOMEDIR/start -crk > /dev/null"
  26456. X.in -2
  26457. X.fi
  26458. X.sp
  26459. XTo force requests to get processed now:
  26460. X.sp
  26461. X.nf
  26462. X.in +2
  26463. Xrun-listproc: "|HOMEDIR/listproc -1 > /dev/null"
  26464. X.in -2
  26465. X.fi
  26466. X.sp
  26467. XTo start the queue daemon:
  26468. X.sp
  26469. X.nf
  26470. X.in +2
  26471. Xproc-queue: "|HOMEDIR/queued 60 & > /dev/null"
  26472. X.in -2
  26473. X.fi
  26474. X.sp
  26475. XThese aliases should be hard to guess for obvious reasons. The actual
  26476. Xmessage sent to such an alias is discarded.
  26477. X.SH EXIT\ CODES
  26478. XAll applications except tlock use the following exit codes for communication:
  26479. X.sp
  26480. X.TP
  26481. X0
  26482. X- OK, normal exit
  26483. X.TP
  26484. X1
  26485. X- Could not open or lock file
  26486. X.TP
  26487. X2
  26488. X- SIGINT signal (normal termination)
  26489. X.TP
  26490. X3
  26491. X- Command line option error
  26492. X.TP
  26493. X4
  26494. X- Syntax error in file
  26495. X.TP
  26496. X5
  26497. X- Could not spawn (restart failed)
  26498. X.TP
  26499. X6
  26500. X- Shutdown request
  26501. X.TP
  26502. X7
  26503. X- Restart request
  26504. X.TP
  26505. X8
  26506. X- Received system signal (anything but SIGINT will bring the system down)
  26507. X.TP
  26508. X9
  26509. X- Too many multiple recipients
  26510. X.TP
  26511. X10
  26512. X- Could not deliver mail (unexpected reply during the SMTP transaction)
  26513. X.TP
  26514. X11
  26515. X- malloc() failed
  26516. X.TP
  26517. X12
  26518. X- Cannot fork()
  26519. X.TP
  26520. X13
  26521. X- Socket connection problem
  26522. X.TP
  26523. X14
  26524. X- Semaphore error
  26525. X.TP
  26526. X15
  26527. X- Cannot setuid()/setgid()
  26528. X.TP
  26529. X16
  26530. X- Internal error or system call failure
  26531. X.fi
  26532. X.PP
  26533. Xtlock exits with:
  26534. X.TP
  26535. X-1
  26536. X- File locking not functional
  26537. X.TP
  26538. X0
  26539. X- No files locked
  26540. X.TP
  26541. X1
  26542. X- Cannot open config
  26543. X.TP
  26544. X2 & up
  26545. X- Number of files locked + 1
  26546. X.SH REPORTS
  26547. XThe system provides two ways of reporting progress: via syslog(3) when available
  26548. X(by compiling with -DSYSLOG=facility) with priority LOG_INFO and facility as
  26549. Xspecified, or through its own report files (when not using syslog(3)); these
  26550. Xare:
  26551. X.TP
  26552. XHOMEDIR/.report.catmail
  26553. XMessages from \fIcatmail\fP(1) every time new messages are appended to the
  26554. Xvarious mail files.
  26555. X.TP
  26556. XHOMEDIR/.report.daemon
  26557. XMessages from \fIserverd\fP(1) every time new mail has arrived.
  26558. X.TP
  26559. XHOMEDIR/.report.list
  26560. XError messages from \fIlist\fP(1) when attempting to process public messages.
  26561. X.TP
  26562. XHOMEDIR/.report.pqueue
  26563. XMessages from \fIpqueue\fP (see \fIqueue\fP(1)).
  26564. X.TP
  26565. XHOMEDIR/.report.server
  26566. XMessages from \fIlistproc\fP(1) every time new requests are processed.
  26567. X.TP
  26568. XHOMEDIR/.report.start
  26569. XGenerated by \fIstart\fP(1) every time the system is started.
  26570. X.TP
  26571. XHOMEDIR/lists/LIST_ALIAS/.report.list
  26572. XMessages from \fIlist\fP(1) when processing public messages.
  26573. X.TP
  26574. XHOMEDIR/.*.acc
  26575. XAccumulated reports since the system was first installed.
  26576. X.TP
  26577. XHOMEDIR/lists/*/.*.acc
  26578. XAccumulated reports for each mailing list.
  26579. X.PP
  26580. XEvery report includes a time stamp; every list and server report also
  26581. Xincludes the actual sender of the message, and every server report
  26582. Xincludes all requests made by the sender.
  26583. X.PP
  26584. XWhenever a program dies abnormally (and BSD mail is present) a message
  26585. Xis sent to \fImanager\fP (as defined in \fIconfig\fP). 
  26586. XThe message is usually sent by \fIserverd\fP(1) which
  26587. Xthen exits. The daemon dies with a different message according to the exit
  26588. Xstatus of the child; the various error conditions that may occur are:
  26589. X.TP
  26590. XCould not open file
  26591. XHOMEDIR is not a valid path; file was accidentally deleted;
  26592. Xinsufficient access privileges. Run \fIsetup\fP and \fIstart\fP.
  26593. X.TP
  26594. XCould not lock file
  26595. XHOMEDIR is not a valid path; file was accidentally deleted;
  26596. Xinsufficient access privileges; another program is using the lock
  26597. Xfile. Run \fItlock\fP, and if necessary, \fIulock\fP; then \fIstart\fP.
  26598. X\fItlock\fP checks for locked files, and \fIulock\fP removes all lock
  26599. Xfiles.
  26600. X.TP
  26601. XCommand line option error
  26602. XCheck the \fIconfig\fP file and restart.
  26603. X.TP
  26604. XSyntax error in file
  26605. XCheck \fIconfig\fP, all reports, .subscribers, .peers and .news files.
  26606. X.TP
  26607. XCould not spawn
  26608. XNo more processes.
  26609. X.TP
  26610. XReceived system signal
  26611. XSIGQUIT, SIGTERM, SIGBUS, SIGSEGV, SIGILL.
  26612. X.SH FILES
  26613. X.TP
  26614. XHOMEDIR/.aliases
  26615. XAliases of email addresses of users having trouble getting replies to requests.
  26616. X.TP
  26617. XHOMEDIR/.awk
  26618. Xawk program for formatting the \fIstatistics\fP request.
  26619. X.TP
  26620. XHOMEDIR/.grep
  26621. Xscript used for counting the number of messages sent by a subscriber.
  26622. X.TP
  26623. XHOMEDIR/.ignored
  26624. XList of unwanted senders.
  26625. X.TP
  26626. XHOMEDIR/.lock.pqueue
  26627. XLock file for \fIpqueue\fP (see \fIqueue\fP(1)).
  26628. X.TP
  26629. XHOMEDIR/.lock.serverd
  26630. XLock file for \fIserverd\fP(1).
  26631. X.TP
  26632. XHOMEDIR/.message.ids
  26633. XA database of recent message id's used to detect mail loops.
  26634. X.TP
  26635. XHOMEDIR/.queue.id
  26636. XNext id to be assigned to next undeliverable message placed in the mqueue/
  26637. Xdirectory.
  26638. X.TP
  26639. XHOMEDIR/.reply.listser
  26640. XThe reply code given to \fIserverd\fP(1) during a live session.
  26641. X.TP
  26642. XHOMEDIR/.rep.server.acc
  26643. XArchived \fIlistproc\fP(1) reports.
  26644. X.TP
  26645. XHOMEDIR/.rep.serverd.acc
  26646. XArchived \fIserverd\fP(1) reports.
  26647. X.TP
  26648. XHOMEDIR/.rep.start.acc
  26649. XArchived \fIstart\fP(1) reports.
  26650. X.TP
  26651. XHOMEDIR/.report.catmail
  26652. XCurrent \fIcatmail\fP(1) report.
  26653. X.TP
  26654. XHOMEDIR/.report.daemon
  26655. XCurrent \fIserverd\fP(1) report.
  26656. X.TP
  26657. XHOMEDIR/.report.list
  26658. XError messages from \fIlist\fP(1).
  26659. X.TP
  26660. XHOMEDIR/.report.server
  26661. XCurrent \fIlistproc\fP(1) report.
  26662. X.TP
  26663. XHOMEDIR/.report.start
  26664. XLast \fIstart\fP(1) action (system started or shut down).
  26665. X.TP
  26666. XHOMEDIR/.stats
  26667. XScript used for the \fIstatistics\fP request.
  26668. X.TP
  26669. XHOMEDIR/.sums
  26670. XDatabase of checksums of public messages.
  26671. X.TP
  26672. XHOMEDIR/.tag.id
  26673. XNext id to be assigned to next moderated message.
  26674. X.TP
  26675. XHOMEDIR/.warning
  26676. XLog of system calls' exit statuses.
  26677. X.TP
  26678. XHOMEDIR/batch
  26679. XBatched user requests.
  26680. X.TP
  26681. XHOMEDIR/catmail
  26682. XIncoming message redirection application.
  26683. X.TP
  26684. XHOMEDIR/config
  26685. XThe configuration file.
  26686. X.TP
  26687. XHOMEDIR/farch
  26688. XFile archiving utility.
  26689. X.TP
  26690. XHOMEDIR/ilp
  26691. XInteractive ListProcessor client; to be used to connect to the
  26692. Xinteractive server.
  26693. X.TP
  26694. XHOMEDIR/list
  26695. XThe mailing list program.
  26696. X.TP
  26697. XHOMEDIR/listproc
  26698. XThe system's request server.
  26699. X.TP
  26700. XHOMEDIR/lost+found
  26701. XRequests that could not be appended to HOMEDIR/requests.
  26702. X.TP
  26703. XHOMEDIR/mbox
  26704. XAn archive of all requests sent to date to ListProcessor.
  26705. X.TP
  26706. XHOMEDIR/news
  26707. XScript used to add a news group to a list.
  26708. X.TP
  26709. XHOMEDIR/owners
  26710. XList of list owners' addresses used for authentication of list maintenance
  26711. Xrequests.
  26712. X.TP
  26713. XHOMEDIR/peer
  26714. XScript used to add a peer list.
  26715. X.TP
  26716. XHOMEDIR/pqueue
  26717. XThe mail queue processing program (see \fIqueue(1)\fP).
  26718. X.TP
  26719. XHOMEDIR/priv.hosts
  26720. XList of hosts that may connect to the interactive part of the system.
  26721. X.TP
  26722. XHOMEDIR/queued
  26723. XThe mail queue processing daemon (see \fIqueue(1)\fP).
  26724. X.TP
  26725. XHOMEDIR/received
  26726. XFile containing the messages received from sendmail during the
  26727. Xlast message distribution -- the \fIsystem\fP mailmethod has to be
  26728. Xin use.
  26729. X.TP
  26730. XHOMEDIR/requests
  26731. XNewly arrived user requests.
  26732. X.TP
  26733. XHOMEDIR/requests.live
  26734. XRepository for requests coming in from live connections.
  26735. X.TP
  26736. XHOMEDIR/sent
  26737. XFile containing the messages sent to sendmail during the
  26738. Xlast message distribution -- the \fIsystem\fP mailmethod has to be
  26739. Xin use.
  26740. X.TP
  26741. XHOMEDIR/serverd
  26742. XThe system's daemon.
  26743. X.TP
  26744. XHOMEDIR/setup
  26745. XSystem setup script.
  26746. X.TP
  26747. XHOMEDIR/start
  26748. XThe system's housekeeping program.
  26749. X.TP
  26750. XHOMEDIR/tlock
  26751. XChecks for any locked files.
  26752. X.TP
  26753. XHOMEDIR/ulock
  26754. XScript to remove all lock files.
  26755. X.TP
  26756. XHOMEDIR/unwanted.hosts
  26757. XList of hosts that may not connect to the interactive part of the system.
  26758. X.TP
  26759. XHOMEDIR/welcome.live
  26760. XWelcoming message upon live connection establishment.
  26761. X.TP
  26762. XHOMEDIR/archives/listproc/DIR
  26763. XDirectory of all files available from the master archive (listproc).
  26764. X.TP
  26765. XHOMEDIR/archives/listproc/INDEX
  26766. XThe master archive index.
  26767. X.TP
  26768. XHOMEDIR/doc/catmail.1
  26769. XMan page source for \fIcatmail\fP(1).
  26770. X.TP
  26771. XHOMEDIR/doc/catmail.nr
  26772. XFormatted man page for \fIcatmail\fP(1).
  26773. X.TP
  26774. XHOMEDIR/doc/farch.1
  26775. XMan page source for the \fIfarch\fP(1) utility.
  26776. X.TP
  26777. XHOMEDIR/doc/farch.nr
  26778. XFormatted man page for the \fIfarch\fP(1) utility.
  26779. X.TP
  26780. XHOMEDIR/doc/ilp.1
  26781. XMan page source for the \fIilp\fP(1) utility.
  26782. X.TP
  26783. XHOMEDIR/doc/ilp.nr
  26784. XFormatted man page for \fIilp\fP(1).
  26785. X.TP
  26786. XHOMEDIR/doc/list.1
  26787. XMan page source for \fIlist\fP(1).
  26788. X.TP
  26789. XHOMEDIR/doc/list.nr
  26790. XFormatted man page for \fIlist\fP(1).
  26791. X.TP
  26792. XHOMEDIR/doc/listproc.1
  26793. XMan page source for \fIlistproc\fP(1).
  26794. X.TP
  26795. XHOMEDIR/doc/listproc.nr
  26796. XFormatted man page for \fIlistproc\fP(1).
  26797. X.TP
  26798. XHOMEDIR/doc/queue.1
  26799. XMan page source for \fIpqueue\fP and \fIqueued\fP(1).
  26800. X.TP
  26801. XHOMEDIR/doc/queue.nr
  26802. XFormatted man page for \fIpqueue\fP and \fIqueued\fP(1).
  26803. X.TP
  26804. XHOMEDIR/doc/server.1
  26805. XSource of the system's main man page.
  26806. X.TP
  26807. XHOMEDIR/doc/server.nr
  26808. XFormatted main man page.
  26809. X.TP
  26810. XHOMEDIR/doc/serverd.1
  26811. XMan page source for \fIserverd\fP(1).
  26812. X.TP
  26813. XHOMEDIR/doc/serverd.nr
  26814. XFormatted man page for \fIserverd\fP(1).
  26815. X.TP
  26816. XHOMEDIR/doc/start.1
  26817. XMan page source for \fIstart\fP(1).
  26818. X.TP
  26819. XHOMEDIR/doc/start.nr
  26820. XFormatted man page for \fIstart\fP(1).
  26821. X.TP
  26822. XHOMEDIR/help/*
  26823. XGeneral and topic-specific help files available upon a \fIhelp\fP
  26824. Xrequest. The TOPICS is a special file where topics are defined.
  26825. X.TP
  26826. XHOMEDIR/lists/LIST_ALIAS/.aliases
  26827. XAliases of email addresses of subscribers.
  26828. X.TP
  26829. XHOMEDIR/lists/LIST_ALIAS/.digest.toc
  26830. XAll the subject lines from the digest. It will be
  26831. Xwritten at the head of the digest when it is sent.
  26832. X.TP
  26833. XHOMEDIR/lists/LIST_ALIAS/.digest.msg
  26834. XAll the messages of the digest, separated by dashed lines.
  26835. X.TP
  26836. XHOMEDIR/lists/LIST_ALIAS/.digest.time
  26837. XThe time that the last digest was sent, represented as the value
  26838. Xreturned by time(2). It is used to calculate when it is time to send
  26839. Xout the next digest.
  26840. X.TP
  26841. XHOMEDIR/lists/LIST_ALIAS/.headers
  26842. XAn archive of who sent each message; used upon a \fIstatistics\fP
  26843. Xrequest.
  26844. X.TP
  26845. XHOMEDIR/lists/LIST_ALIAS/.ignored
  26846. XA list of unwanted senders.
  26847. X.TP
  26848. XHOMEDIR/lists/LIST_ALIAS/.info
  26849. XText sent upon an \fIinformation\fP request.
  26850. X.TP
  26851. XHOMEDIR/lists/LIST_ALIAS/.limits
  26852. XUsed by \fIserverd\fP(1) when placing various limits for the list.
  26853. X.TP
  26854. XHOMEDIR/lists/LIST_ALIAS/.message.ids
  26855. XA database of recent message id's used to detect mail loops.
  26856. X.TP
  26857. XHOMEDIR/lists/LIST_ALIAS/.news
  26858. XA list of all news groups connected to this list.
  26859. X.TP
  26860. XHOMEDIR/lists/LIST_ALIAS/.peers
  26861. XA list of all peer lists for this mailing list,
  26862. Xalong with the email addresses of their servers.
  26863. X.TP
  26864. XHOMEDIR/lists/LIST_ALIAS/.rep.list.acc
  26865. XArchived reports from \fIlist\fP(1).
  26866. X.TP
  26867. XHOMEDIR/lists/LIST_ALIAS/.report.list
  26868. XCurrent report from \fIlist\fP(1).
  26869. X.TP
  26870. XHOMEDIR/lists/LIST_ALIAS/.restricted
  26871. XList of subscribers with alternate recipient files.
  26872. X.TP
  26873. XHOMEDIR/lists/LIST_ALIAS/.subscribers
  26874. XA list of all subscribers along with preferences and settings.
  26875. X.TP
  26876. XHOMEDIR/lists/LIST_ALIAS/.un.digest
  26877. XWhen a digest is constructed, it will be stored in this file until it
  26878. Xhas been sent to all digest subscribers.
  26879. X.TP
  26880. XHOMEDIR/lists/LIST_ALIAS/.welcome
  26881. XText sent on a \fIsubscribe\fP request.
  26882. X.TP
  26883. XHOMEDIR/lists/LIST_ALIAS/archive
  26884. XArchive of all distributed messages since the file was last created.
  26885. X.TP
  26886. XHOMEDIR/lists/LIST_ALIAS/lost+found
  26887. XMail that could not be appended to the 'mail' or 'moderated' files
  26888. X(see next entries and \fIcatmail\fP(1)).
  26889. X.TP
  26890. XHOMEDIR/lists/LIST_ALIAS/mail
  26891. XNewly arrived public messages to be distributed.
  26892. X.TP
  26893. XHOMEDIR/lists/LIST_ALIAS/mbox
  26894. XAn archive of all messages sent to date.
  26895. X.TP
  26896. XHOMEDIR/lists/LIST_ALIAS/moderated
  26897. XNewly arrived public messages that need to be edited before
  26898. Xdistributed.
  26899. X.TP
  26900. XHOMEDIR/lists/LIST_ALIAS/removed.users
  26901. XEntries from the .subscribers file for users who have been automatically
  26902. Xremoved from the list.
  26903. X.TP
  26904. XHOMEDIR/lists/LIST_ALIAS/removed.alias
  26905. XEntries from the .aliases file for users who have been automatically
  26906. Xremoved from the list.
  26907. X.TP
  26908. XHOMEDIR/mqueue/*
  26909. XQueued messages for later delivery.
  26910. X.SH UPGRADING
  26911. XWhen upgrading, it is not necessary to remove your current system.
  26912. XOld key directories and files will be moved elsewhere. Always run the
  26913. X\fIsetup\fP script. In addition, if you are upgrading from:
  26914. X.TP
  26915. X5.5
  26916. XThe system may now go interactive with the -i flag to \fIserverd\fP(1).
  26917. X.sp
  26918. X\fIremote\fP lists may now specify host names or Internet addresses and ports if
  26919. Xthey are served by interactive ListProcessors.
  26920. X.sp
  26921. XThe ULISTPROC_UMASK environment variable is now used. For archives, there is
  26922. XULISTPROC_ARCHIVES_UMASK.
  26923. X.sp
  26924. XThe IUL (\fIilp(1)\fP) client is available to connect to interactive
  26925. XListProcessors.
  26926. X.sp
  26927. XThe \fIhelp\ live\fP request explains how to connect to interactive
  26928. XListProcessors.
  26929. X.sp
  26930. XThe \fIprecedence\fP directive has been added to the \fIconfig\fP file.
  26931. X.sp
  26932. XPrecious header lines are preserved for each list via the \fIheader\fP
  26933. Xdirective.
  26934. X.sp
  26935. XRegular expressions are implemented for the ".aliases" and ".ignored" files.
  26936. X.sp
  26937. XLists may now automaticlly archive distributed messages via the
  26938. X\fIarchive\fP directive.
  26939. X.sp
  26940. XThe manager may allow subscribers of a list to execute UNIX commands via the
  26941. X\fIunix_cmd\fP directive. Users submit a \fIrun\fP request in this case
  26942. X(CCRUN is added as a preference).
  26943. X.sp
  26944. X\fIfarch\fP now creates new archives and takes care of updating and creating
  26945. XDIR and INDEX files as well as directories, and may archive true binary files
  26946. X(does not uuencode them) if requested (-B flag); the -p option was introduced
  26947. Xto accept a password for a new private archive, the -D option to specify
  26948. Xa short description of the files, and the -r option to remove files from
  26949. Xarchives.
  26950. X.sp
  26951. XCommands in the \fIconfig\fP file may span multiple lines if each line is
  26952. Xterminated by &\\n.
  26953. X.sp
  26954. XThe system intercepts requests sent to lists.
  26955. X.sp
  26956. XThe \fIconceal\fP user attribute has been introduced to the subscribers files.
  26957. X.sp
  26958. XThe \fIdefault\fP directive has been introduced to the \fIconfig\fP file to
  26959. Xset default values for new subscribers.
  26960. X.sp
  26961. XUsers may change the address they are subscribed with, if the owner allows this.
  26962. X.sp
  26963. XThe util/ directory has been introduced for general utilities.
  26964. X.sp
  26965. XHelp files may now be shell scripts; same for all lists' ".welcome" and
  26966. X".info" files.
  26967. X.sp
  26968. Xsyslog(3) is now supported for progress reporting by compiling with
  26969. X-DSYSLOG=facility.
  26970. X.sp
  26971. XArchive files may be split on the way out if they exceed the \fIlimit\fP
  26972. Xspecified in the \fIconfig\fP file.
  26973. X.sp
  26974. XLists may restrict the number of messages processed per day with the
  26975. X\fIceiling\fP directive.
  26976. X.sp
  26977. XThe new request \fIfax\fP with its synonymous directive have been introduced.
  26978. X.sp
  26979. XConcealed lists are supported via the -c option to \fIlistproc\fP(1).
  26980. X.sp
  26981. XError messages from mailer daemons are scanned and automatic action is taken
  26982. Xif compiling with -DERROR_MAIL_ANALYSIS=level (1=conservative, 9=full).
  26983. X.sp
  26984. XArchives may now be searched with the \fIsearch\fP request.
  26985. X.sp
  26986. X\fIcatmail\fP will now time out after 2 minutes of idle time (perhaps
  26987. Xdue to OS problems).
  26988. X.sp
  26989. XYou may now turn off compression of archived files and messaged with 
  26990. Xnew flags to \fIfarch\fP and \fIlist\fP.
  26991. X.sp
  26992. XRun the upgrade_to_6.0c script.
  26993. X.TP
  26994. X5.41
  26995. XModerated lists are now owner controlled, rather than manager controlled.
  26996. X.sp
  26997. XManager preferences have now been introduced.
  26998. X.sp
  26999. XSee the UPGRADING section in \fIfarch(1)\fP.
  27000. X.sp
  27001. XFollow the upgrade instructions for 5.5
  27002. X.TP
  27003. X5.4
  27004. X\fIcatmail\fP(1) has been implemented, therefore the various aliases
  27005. Xin the aliases file have to be redefined (as explained above) to
  27006. Xtake advantage.
  27007. X.sp
  27008. XOwner preferences have been introduced in the \fIowners\fP file.
  27009. X.sp
  27010. XFollow the upgrade instructions for 5.41
  27011. X.TP
  27012. X5.31
  27013. XThe \fIlist\fP directive in the \fIconfig\fP file now takes two extra
  27014. Xarguments: the list owner's address, and the list's access password.
  27015. X.sp
  27016. X\fIqueued\fP now takes only one argument, a frequency count.
  27017. X.sp
  27018. XThe system supports 10 lists by default (see LIMITATIONS below);
  27019. Xif you are currently using the maximum supported number of lists, consult
  27020. Xthe HOMEDIR/src/defs.h file.
  27021. X.sp
  27022. XThe layout and structure of INDEX files has been extended; see
  27023. X\fIfarch(1)\fP for more information.
  27024. X.sp
  27025. XFollow the upgrade instructions for 5.4
  27026. X.TP
  27027. X5.3
  27028. XThe \fIlist\fP directive in the \fIconfig\fP file now takes two extra
  27029. Xarguments: the list owner's address, and the list's access password.
  27030. X.sp
  27031. XThe system supports 10 lists by default (see LIMITATIONS below);
  27032. Xif you are currently using the maximum supported number of lists, consult
  27033. Xthe HOMEDIR/src/defs.h file.
  27034. X.sp
  27035. XThe layout and structure of INDEX files has been extended; see
  27036. X\fIfarch(1)\fP for more information.
  27037. X.sp
  27038. XFollow the upgrade instructions for 5.4
  27039. X.TP
  27040. X5.2\*
  27041. XUse the \fIsystem\fP mailmethod.
  27042. X.sp
  27043. XFor every list you need to edit HOMEDIR/lists/LIST_ALIAS/.ignored
  27044. Xand add one more entry: the full email address of the server account.
  27045. X.sp
  27046. XFollow the upgrade instructions for 5.3
  27047. X.TP
  27048. X5.0, 5.1\*
  27049. XFor every list you need to edit
  27050. XHOMEDIR/lists/LIST_ALIAS/.ignored and add
  27051. Xtwo entries: the actual list alias, and the full email address
  27052. Xof this list.
  27053. X.sp
  27054. X\fIneverack\fP is not a valid mail mode anymore. Change every
  27055. Xoccurrence in ".subscribers" to NOACK, for every list.
  27056. X.sp
  27057. XAny peer lists and/or news groups appearing in ".subscribers"
  27058. Xshould be removed; use the \fIpeer\fP and \fInews\fP scripts
  27059. Xto put them back.
  27060. X.sp
  27061. X\fIserverd\fP, \fIlist\fP and \fIlistproc\fP no longer report to the
  27062. Xstdout by default -- use the -e command line option.
  27063. X.sp
  27064. XFollow the upgrade instructions for 5.2
  27065. X.SH PORT\ SPECIFIC
  27066. XFor various compilation options, consult the src/Makefile.
  27067. XStarting with version 5.3, a universal mailmethod was introduced: \fIsystem\fP;
  27068. XIt should be used in every system that has TCP/IP installed,
  27069. Xas it has been verified to work on
  27070. Xmany systems below -- consult the src/README file.
  27071. X.TP
  27072. XIBM Risc
  27073. XYou should use \fIsysv_ps\fP as an option in the \fIconfig\fP file,
  27074. Xand compile with xlc -D_ALL_SOURCE -qnoro. You have to use \fIsystem\fP
  27075. Xas the mailmethod.  Messages distributed to local
  27076. Xsubscribers on the system may see their messages arrive "From root...",
  27077. Xbut all other subscribers in the outside world will see "From listproc@..."
  27078. Xand/or "From list@..." which is the correct header. If you use
  27079. X\fIenv_var\ LOGNAME\ /bin/rmail\fP instead, the behavior will be reversed.
  27080. X\fItelnet\fP may not be used as a mailmethod. Compile with -DHAVE_SELECT_H,
  27081. X-DHAVE_ULIMIT_H -DSETPGRP_NEEDS_ARGS and -DHAVE_SETJMP_H, and link with -lbsd.
  27082. XIn defs.h the system is defined as having an SVR3 flavor.
  27083. X.TP
  27084. XSGI
  27085. XYou have to use the \fIsystem\fP mailmethod.
  27086. XAll Irix versions to date seem to have a serious problem with telnet (it
  27087. Xcorrupts file descriptors). Use the \fIsysv_ps\fP option.
  27088. XIn the Makefile, for IRIX 4, define the symbol CC to be 'cc -ansi' or 'cc
  27089. X-D__STDC__', and compile with -DHAVE_SETJMP_H and -D_POSIX_SOURCE; for IRIX 5,
  27090. Xcompile with 'cc -D_BSD_SOURCE -Dsvr4' and all other flags found by systest.
  27091. XIn defs.h the system is defined as having an SVR3 flavor.
  27092. X.TP
  27093. XSUN
  27094. X\fIsystem\fP and \fItelnet\fP work fine as mailmethods.
  27095. XUse the \fIbsd_ps\fP option. The server user id should not be the same
  27096. Xas root's.
  27097. XIf you use the native cc compiler you will need to convert to K&R C
  27098. X(by using the unproto system -- consult the src/Makefile);
  27099. Xotherwise /usr/lang/acc -w (ANSI C) can be used. Compile with -DHAVE_SETJMP_H
  27100. Xand -DSETPGRP_NEEDS_ARGS.
  27101. XIn defs.h the system is defined as having a BSD flavor. On Solaris 5.2 and
  27102. Xabove, compile with -Dsvr4 only. If using the live part of the system and
  27103. Xyour host is a YP/NIS client you should put the new service in the master's
  27104. Xservices map, or if on the master, remake the map. Older versions of SUNOS have
  27105. Xproblems with their include files, and in this case you have to comment out
  27106. Xthe line:
  27107. X.sp
  27108. X#include <netdb.h>
  27109. X.sp
  27110. Xin src/*.c
  27111. X.TP
  27112. XDECstations
  27113. XYou have to use \fIsystem\fP as the mailmethod; if you use
  27114. X\fItelnet\fP instead, you may have to use the \fIbad_telnet\fP
  27115. Xoption; \fIbsd_ps\fP should be used. Ultrix 3.0 has lots of system bugs
  27116. Xand you may experience strange behavior; the file locking mechanism
  27117. Xover NFS appears to be non-standard and is disabled by default; upgrade to 4.2A
  27118. Xis recommended.
  27119. XAn ANSI C compiler should be used. If you are using the unproto system,
  27120. Xuse the -nocpp flag to cc when compiling. Compile with -DHAVE_SETJMP_H and 
  27121. X-DSETPGRP_NEEDS_ARGS.
  27122. XIn defs.h the system is defined as having a BSD flavor. All Bourne shell scripts
  27123. Xmay need to be altered to invoke /bin/sh5, before they are used.
  27124. X.TP
  27125. XConvex
  27126. XIt is suggested that you use the \fIstds\fP script (available via anonymous ftp
  27127. Xfrom cs-ftp.bu.edu) and the non-ANSI compiler; \fIstds\fP should be used as follows:
  27128. X.sp
  27129. Xstds src/nonansi/*.h src/*.c
  27130. X.sp
  27131. XThis should be done after redefining the HOMEDIR entry in src/Makefile and
  27132. Xrunning setup to make all the necessary changes. Compiling under
  27133. XANSI standards (-std flag) is not recommended, since system
  27134. Xinclude files are not ANSI-C compliant. The system cannot go interactive
  27135. Xsince the system does not support semaphores. \fIsystem\fP works fine as
  27136. Xa mailmethod. paste(1) is missing and \fIstatistics\fP requests will
  27137. Xlook erroneous.
  27138. X.TP
  27139. XStardent GS series
  27140. X\fIsystem\fP and \fItelnet\fP work fine as mailmethods.
  27141. XUse the \fIsysv_ps\fP option. The unproto system has to be used (consult
  27142. Xthe src/Makefile) if not using an ANSI C compiler. The system cannot
  27143. Xgo interactive due to a system() bug. In defs.h the system
  27144. Xis defined as having an SVR3 flavor.
  27145. X.TP
  27146. XStardent/KPC Titan series
  27147. X\fIsystem\fP and \fIenv_var\ LOGNAME\ /bin/rmail\fP work fine as mailmethods.
  27148. XUse the \fIsysv_ps\fP option. The system cannot go interactive due to the
  27149. Xabsence of waitpid(), and compiling and linking with -43 (to use wait3())
  27150. Xhangs \fIserverd(1)\fP and the other applications.
  27151. XIn defs.h the system is defined as having an SVR3 flavor.
  27152. X.TP
  27153. XNeXT
  27154. X\fItelnet\fP, \fIsendmail\fP, \fIsystem\fP (if TCP/IP is installed and SMTP is
  27155. Xused) work fine as mailmethods; however, 'mailmethod sendmail
  27156. X/usr/lib/sendmail -ba' has been characterized as a "DISASTER in terms of
  27157. Xhogging the cpu." Compile with
  27158. X-D__NeXT__ if your compiler does not define this symbol (under version 3.0
  27159. Xof the OS this symbol is automatically defined -- 3.0 is the only supported
  27160. Xenvironment). Compile with -I/usr/include/bsd and -I/usr/include/bsd/sys and
  27161. X-DSETPGRP_NEEDS_ARGS.
  27162. XFile locking is turned off because of an OS bug.
  27163. XIn defs.h the system is defined as having a BSD flavor. The system
  27164. Xcannot go interactive due to lack of semaphore support.
  27165. X.TP
  27166. XHP-UX
  27167. XCompile with -Aa, -D_HPUX_SOURCE, -DHAVE_ULIMIT_H, -DHAVE_SETJMP_H.
  27168. X\fIsystem\fP is the mailmethod to use.
  27169. XIn defs.h the system is defined as having a BSD flavor.
  27170. X.TP
  27171. XSCO
  27172. XCompile with -Dsco and possibly with -I/usr/include/netinet.
  27173. XYou may wish to link with a
  27174. Xspecial libbsd.a which can be obtained from /pub/sco-ports/libbsd on
  27175. Xdribble.c-mols.siu.edu (131.230.93.2). You need to link with -lsocket.
  27176. XIn defs.h the system is defined as having an SVR3 flavor. The port was done
  27177. Xunder SCO version 3.2.4. The interactive part seems to hang for no apparent
  27178. Xreason.
  27179. X.TP
  27180. XApollo
  27181. XUse the \fIsystem\fP mailmethod. Do not compile with -A ansi, or if you do
  27182. Xalso compile with -Dapollo. The OS that the port was performed under was
  27183. XSR10.4 and version 6.8 of cc. The server id's path should include
  27184. X/sys5.3/usr/bin so that 'paste' may be found. In defs.h the system is defined
  27185. Xas having a BSD flavor. The system cannot go interactive due to lack of
  27186. Xsemaphore support.
  27187. X.TP
  27188. XXenix
  27189. XCompile with -Dxenix; grep(1) is buggy and is suggested that another version
  27190. Xis used. In defs.h the system is defined as having an SVR3 flavor.
  27191. X.TP
  27192. XSequent
  27193. XCompile with gcc -fwritable-strings and -Dsequent if the compiler does not
  27194. Xdefine this symbol. In defs.h
  27195. Xthe system is given a BSD flavor. If under Dynix/PTX, compile with -Dsvr3
  27196. X(PTX is a a System V R3.2 implementation; V2.0.3 includes an ANSI C compiler).
  27197. X.TP
  27198. XData General
  27199. XCompile using gcc -fwritable-strings; in defs.h the system is given an SVR4
  27200. Xflavor and is advisable not to give it a BSD one; keep in mind that
  27201. Xsignals frequently get lost.
  27202. X.TP
  27203. Xi860
  27204. XThis is a standard SVR4 UNIX; \fIsystem\fP works fine as mailmethod. All
  27205. Xfeatures are functional.
  27206. X.TP
  27207. Xi386
  27208. XThis is a BSD environment; the system cannot go interactive due
  27209. Xto lack of semaphore support, and file locking is turned off. \fIsystem\fP
  27210. Xworks fine as mailmethod. Compile with the -fwritable-strings flag.
  27211. X.TP
  27212. XOSF
  27213. XThis is a standard SVR3 UNIX; \fIsystem\fP works fine as mailmethod. All
  27214. Xfeatures are functional. Compile with the -std1 flag. Do not compile with
  27215. X-DHAVE_SELECT_H because of missing system header files, but compile with
  27216. X-DSETPGRP_NEEDS_ARGS.
  27217. X.TP
  27218. XOther
  27219. XFirst, attempt compiling with -Dunknown_port.
  27220. X.SH LIMITATIONS
  27221. X\-
  27222. XUp to 10 mailing lists can be supported (configurable in
  27223. Xsrc/defs.h and src/Makefile).
  27224. X.sp
  27225. X\-
  27226. XThe system assumes a length of 32 bits or higher for long integers.
  27227. X.sp
  27228. X\-
  27229. XA list alias may not be called "server".
  27230. X.SH COMPILER
  27231. X.TP
  27232. Xgcc
  27233. XIf you are using gcc to compile, use the -fwritable-strings flag. Versions
  27234. Xprior to 2.2.1 may cause problems.
  27235. X.SH MAILER
  27236. X.TP
  27237. XZmailer
  27238. XIf you are using the Zmailer to send mail, or any other mailer (like Smail)
  27239. Xthat requires a 'HELO hostname' to start the SMTP transaction,
  27240. Xcompile with -DZMAILER (also see src/README and src/Makefile).
  27241. X.SH REQUIREMENTS
  27242. XThe $path for the server account should include all necessary paths to
  27243. Xcut(1), paste(1), awk(1), grep(1), uptime(1) and telnet(1).
  27244. XIn addition, uptime(1) should report the number of users and the system
  27245. Xload; otherwise \fIserverd\fP(1) cannot be run with the -l option, and
  27246. X\fIlistproc\fP(1) cannot be run with the -r option. The output from uptime
  27247. Xshould look like:
  27248. X.nf
  27249. X.sp
  27250. X12:45pm up 5 days, 16 mins, 4 users, load average: 0.00, ...
  27251. X.sp
  27252. X.fi
  27253. XAlso, make sure that when posting, /usr/lib/news/\fIinews\fP exists either
  27254. Xas itself or as a link to wherever \fIinews\fP resides (also see src/Makefile).
  27255. X.sp
  27256. XFinally, grep(1) should support the -i (case insensitive matching) and
  27257. X-v (print all lines that do not match the expression) flags.
  27258. X.SH BUGS
  27259. X.TP
  27260. Xuptime
  27261. XWhen user and load restrictions are enforced, the system assumes
  27262. Xthat uptime outputs a line similar to the one shown above.
  27263. X.TP
  27264. Xblanks
  27265. XAlthough the system handles email addresses with blanks in them fairly
  27266. Xwell, \fIstatistics\fP, \fIrecipients\fP and \fIset\ list\fP (status
  27267. Xquery) requests will show erroneous results for these users.
  27268. X.TP
  27269. Xspecial characters
  27270. XThe system does not accept addresses that contain single quotes, back-quotes
  27271. Xor wild characters.
  27272. X.TP
  27273. Xmessages exceeding limits not caught
  27274. XWhen all subscribers of a list have set their mail mode to \fIdigest\fP,
  27275. Xmessages are not subject to size limitations.
  27276. X.TP
  27277. Xno \fIstatistics\fP request for NeXT 2.1 hosts
  27278. XDue to the absense of cut(1) the \fI.stats\fP script has to be
  27279. Xmodified to replace the use of cut(1) with awk(1).
  27280. X.TP
  27281. X\fIserverd\fP(1) dies with 'no tty' error message
  27282. XIn the \fIconfig\fP file use the -e flag in the \fIlist\fP, \fIserver\fP and
  27283. X\fIserverd\fP definitions followed by '> /dev/null 2>&1'. For example:
  27284. X.sp
  27285. X.ce
  27286. Xserverd -i 600 -e > /dev/null 2>&1
  27287. X.TP
  27288. Xincorrect auto-splitting of files on the way out
  27289. XWhen splitting files that exceed the specified limit, the system precalculates
  27290. Xthe number of parts it will send and puts this number in the Subject: line.
  27291. XHowever, since each part may actually be less than that limit (each part
  27292. Xextends to the nearest newline without exceeding the limit) it is possible to
  27293. Xsend more parts than predicted, if the total number of bytes backtracked (for
  27294. Xall parts) is an integer multiple of the limit; in this case the number of
  27295. Xextra parts will be this integer multiple. The probability of this happening
  27296. Xincreases as the limit is decreased.
  27297. X.SH SEE\ ALSO
  27298. Xcatmail(1), farch(1), ilp(1), list(1), listproc(1), queue(1), serverd(1),
  27299. Xstart(1)
  27300. X.SH AUTHOR
  27301. X.nf
  27302. XAnastasios C. Kotsikonas
  27303. XCopyright (c) 1991-93, Anastasios Kotsikonas
  27304. XComments to tasos@cs.bu.edu
  27305. X.fi
  27306. *-*-END-of-doc/server.1-*-*
  27307. echo x - doc/serverd.1
  27308. sed 's/^X//' >doc/serverd.1 <<'*-*-END-of-doc/serverd.1-*-*'
  27309. X.\" ListProcessor System
  27310. X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
  27311. X.\"
  27312. X.TH serverd 1 "ListProcessor"
  27313. X.SH NAME
  27314. X\fBserverd\fP \- ListProcessor system daemon
  27315. X.SH SYNOPSIS
  27316. X\fBserverd\fP [\fB-1\fP] [\fB-e\fP] [\fB-l load\fP] [\fB-i duration\fP]
  27317. X.SH DESCRIPTION:
  27318. X\fIserverd\fP silently looks for any new messages for the request
  27319. Xserver and for any of the supported mailing lists, checks whether
  27320. Xthe time has arrived for processing the batch queue, whether
  27321. Xdigest time has been reached for the various lists, and whether any
  27322. Xlive TCP/IP connections are requested. It then spawns
  27323. X\fIlistproc\fP(1) and/or \fIlist\fP(1) as necessary, and sleeps until the
  27324. Xmessage(s) is (are) processed. \fIserverd\fP reads the \fIconfig\fP file
  27325. X(see \fIserver\fP(1)).
  27326. X.SH OPTIONS
  27327. XThe following command line options are recognized:
  27328. X.TP
  27329. X-1
  27330. XExecute only once -- to be used with cron(1).
  27331. X.TP
  27332. X-e
  27333. XEcho reports to the screen; it has no effect if the system has been compiled
  27334. Xwith -DSYSLOG.
  27335. X.TP
  27336. X-l load
  27337. XEnforce load restrictions; \fIserverd\fP will postpone spawning if the
  27338. Xsystem load is above the limit specified.
  27339. X.TP
  27340. X-i duration
  27341. XA child process is also spawned which listens for live TCP/IP connections
  27342. Xat port 372 (this is referred to as the Listsener process, and its parent as
  27343. Xthe Master); for each such connection a child process is created to
  27344. Xprocess the live requests (see the INTERACTIVE\ LISTPROC section below). The
  27345. Xmaximum \fIduration\fP time is given in seconds.
  27346. X.SH INTERACTIVE\ LISTPROC
  27347. XProvided that the host supports the TCP/IP protocol, the system provides
  27348. Xa mechanism for processing live requests by specifying the -i flag to
  27349. X\fIserverd\fP. Any user may use \fItelnet\fP(1) to connect to a host
  27350. Xthat runs this system at port number 372, issue requests as he would
  27351. Xby email, and receive responses immediately. However, the proper way
  27352. Xto connect to the server is by using \fIilp\fP(1) which lets the user download
  27353. Xfiles through \fIget\fP requests, and provides other amenities as well.
  27354. X.PP
  27355. XWhat requests are allowed
  27356. Xdepends on the privileges assigned upon login: the user is asked for
  27357. Xan email address (default is no email address); then a password should be
  27358. Xprovided. If the user needs manager privileges, he has to provide both the
  27359. Xmanager's email address and the system's password as they appear in the
  27360. X\fIconfig\fP file. If he wishes owner privileges, he has to provide both
  27361. Xhis email address as it appears in the \fIowners\fP file and his list's
  27362. Xpassword as it appears in the \fIconfig\fP file. To gain subscriber privileges
  27363. Xhe has to provide his email address as subscribed to the list where privileges
  27364. Xare to be granted to, as well as the password \fIset\fP for that list.
  27365. X.PP
  27366. XA mismatch or no email address reduces privileges to a minimum. These
  27367. Xare restricted to \fIhelp\fP, \fIinformation\fP, \fIrecipients\fP and
  27368. X\fIstatistics\fP for nonprivate lists, \fIlists\fP, \fIindex\fP, \fIget\fP,
  27369. X\fIview\fP, \fIrun\fP and \fIrelease\fP requests. Subscriber privileges extend
  27370. Xthese to \fIset\fP, \fIrun\fP, \fIunsubscribe\fP and \fIwhich\fP requests.
  27371. XOwners are granted permission to also issue \fIsystem\fP, \fIreports\fP,
  27372. X\fIedit\fP, \fIput\fP, \fIapprove\fP and \fIdiscard\fP requests in
  27373. Xaddition to the ones above. Finally, the \fImanager\fP may issue any
  27374. Xrequest except \fIexecute\fP.
  27375. X.PP
  27376. XRequests for remote lists are serviced by attempting to connect to the
  27377. Xremote servers serving these lists.
  27378. X.PP
  27379. XThe system may restrict connections to certain hosts, and/or reject connections
  27380. Xfrom certain hosts. First, the system looks for the file \fIpriv.hosts\fP
  27381. Xwhich lists hostnames and/or IP addresses that are allowed access; only
  27382. Xhosts listed in this file are granted acces. For example, to allow access to
  27383. Xhosts on one's local network only, one could do:
  27384. X.sp
  27385. X.ce
  27386. Xln -s /etc/hosts HOMEDIR/priv.hosts
  27387. X.sp
  27388. XNext, the file \fIunwanted.hosts\fP is looked up, and connections from hosts
  27389. Xlisted in it are rejected. Regular expressions may be used in both files.
  27390. X.sp
  27391. XThe duration of each connection is limited to the number of seconds
  27392. Xgiven as argument to the -i flag. A maximum of 5 simultaneous connections
  27393. Xcan be accepted at any time. All requests are serialized and the server may
  27394. Xbe kept busy if it has not finished sending data to a socket (for example,
  27395. Xwhen a user pipes the output he receives to more(1) and the amount of data 
  27396. Xto be sent is more than the the socket's buffer).
  27397. X.PP
  27398. XTo set up your system to accept such connections, the following line has to
  27399. Xbe inserted into your host's /etc/services file:
  27400. X.sp
  27401. X.ce
  27402. Xulistproc   372/tcp
  27403. X.sp
  27404. XThis port is privileged, therefore \fIserverd\fP has to be started with
  27405. Xroot privileges (the \fIsetup\fP script takes care of this). If you do not
  27406. Xhave root access you may choose any other port number above 1024, and in
  27407. Xthis case \fIserverd\fP will give a warning every time it starts, which
  27408. Xcan be ignored.
  27409. X.PP
  27410. XConsult the src/README file for qualification tests for your system to go
  27411. Xinteractive and the Makefile for compilation options; also see the
  27412. XPORT\ SPECIFIC section in \fIserver\fP(1). Lastly, the file HOMEDIR/welcome.live
  27413. Xis copied upon log in, and it may be modified.
  27414. X.PP
  27415. XIf your setup uses a name server you may wish to link with libraries that
  27416. Xprovide DNS support.
  27417. X.SH SEE\ ALSO
  27418. Xilp(1), list(1), listproc(1), queue(1), server(1)
  27419. X.SH AUTHOR
  27420. X.nf
  27421. XAnastasios C. Kotsikonas
  27422. XCopyright (c) 1991-93, Anastasios Kotsikonas
  27423. XComments to tasos@cs.bu.edu
  27424. X.fi
  27425. *-*-END-of-doc/serverd.1-*-*
  27426. echo x - doc/start.1
  27427. sed 's/^X//' >doc/start.1 <<'*-*-END-of-doc/start.1-*-*'
  27428. X.\" ListProcessor System
  27429. X.\" Copyright (c) 1991-93, Anastasios Kotsikonas
  27430. X.\"
  27431. X.TH start 1 "ListProcessor"
  27432. X.SH NAME
  27433. X\fBstart\fP \- start/stop the ListProcessor system
  27434. X.SH SYNOPSIS
  27435. X\fBstart\fP [\fB-c\fP] [\fB-r\fP] [\fB-k\fP]
  27436. X.SH DESCRIPTION
  27437. X\fIstart\fP is used to start or stop the ListProcessor system.
  27438. XWhen starting the system, any
  27439. Xprevious server processes still running are killed, all necessary
  27440. Xlock files are created, any previous reports are archived into files with
  27441. Xextension \fI.acc\fP, new files and directories are created for any
  27442. Xnew mailing lists, and \fIserverd\fP(1) is spawned. \fIstart\fP reads the
  27443. X\fIconfig\fP file (see \fIserver(1)\fP), and should always be run from the server
  27444. Xaccount.
  27445. X.SH OPTIONS
  27446. XThe following command line options are recognized:
  27447. X.TP
  27448. X-c
  27449. XSuppress confirmation when killing processes or when creating new
  27450. Xmailing list directories and files.
  27451. X.TP
  27452. X-k
  27453. XJust kill any old server system processes and exit.
  27454. X.TP
  27455. X-r
  27456. XRestrict reporting to stdout.
  27457. X.SH SEE\ ALSO
  27458. Xserver(1), serverd(1)
  27459. X.SH AUTHOR
  27460. X.nf
  27461. XAnastasios C. Kotsikonas
  27462. XCopyright (c) 1991-93, Anastasios Kotsikonas
  27463. XComments to tasos@cs.bu.edu
  27464. X.fi
  27465. *-*-END-of-doc/start.1-*-*
  27466. echo x - doc/catmail.nr
  27467. sed 's/^X//' >doc/catmail.nr <<'*-*-END-of-doc/catmail.nr-*-*'
  27468. X
  27469. X
  27470. X
  27471. Xcatmail(1)               USER COMMANDS                 catmail(1)
  27472. X
  27473. X
  27474. X
  27475. XNNNNAAAAMMMMEEEE
  27476. X     ccccaaaattttmmmmaaaaiiiillll - append incoming mail to ListProcessor system files
  27477. X
  27478. XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
  27479. X     ccccaaaattttmmmmaaaaiiiillll {<----LLLL LLLLIIIISSSSTTTT____AAAALLLLIIIIAAAASSSS [----mmmm]> | <----rrrr>} [----ffff]
  27480. X
  27481. XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
  27482. X     _c_a_t_m_a_i_l is used to redirect incoming mail to the ListProces-
  27483. X     sor  system to the appropriate files, according to the flags
  27484. X     specified. The files affected are HOMEDIR/requests (a  repo-
  27485. X     sitory  for requests), HOMEDIR/lists/*/mail (public messages
  27486. X     to be distributed) and  HOMEDIR/lists/*/moderated  (messages
  27487. X     to be screened out by a moderator). _c_a_t_m_a_i_l reports the user
  27488. X     id and user name that is currently executing it; the  setuid
  27489. X     bit  has  to  be set when installed. _c_a_t_m_a_i_l first locks the
  27490. X     output file before appending to it; if the  file  cannot  be
  27491. X     locked   after   3   minutes,   the   mail  is  saved  under
  27492. X     HOMEDIR/lost+found or HOMEDIR/lists/*/lost+found; both  _l_i_s_t
  27493. X     and  _l_i_s_t_p_r_o_c  lock their mail files while copying them to a
  27494. X     safe place. _c_a_t_m_a_i_l will time out after 2 minutes  to  avoid
  27495. X     deadlock situations, and the mail message may be returned to
  27496. X     the sender as undeliverable.
  27497. X
  27498. XOOOOPPPPTTTTIIIIOOOONNNNSSSS
  27499. X     The following command line options are recognized:
  27500. X
  27501. X     -L LIST_ALIAS [-m]
  27502. X          If  the  -m  flag   is   not   specified,   append   to
  27503. X          HOMEDIR/lists/_L_I_S_T__A_L_I_A_S/mail;   otherwise   append  to
  27504. X          HOMEDIR/lists/_L_I_S_T__A_L_I_A_S/moderated (see _l_i_s_t(_1)).
  27505. X
  27506. X     -r   Append to HOMEDIR/requests (overrides -L).
  27507. X
  27508. X     -f   Reformat the message in the process: all lines  in  the
  27509. X          message except the first starting with "From " are con-
  27510. X          verted  to  ">From  ".   (see  also   SYSTEM SETUP   in
  27511. X          _s_e_r_v_e_r(1)).
  27512. X
  27513. XSSSSEEEEEEEE AAAALLLLSSSSOOOO
  27514. X     list(1), listproc(1), server(1)
  27515. X
  27516. XAAAAUUUUTTTTHHHHOOOORRRR
  27517. X     Anastasios C. Kotsikonas
  27518. X     Copyright (c) 1991-93, Anastasios Kotsikonas
  27519. X     Comments to tasos@cs.bu.edu
  27520. X
  27521. X
  27522. X
  27523. X
  27524. X
  27525. X
  27526. X
  27527. X
  27528. X
  27529. X
  27530. XAnastasios Kotsikonas                                               1
  27531. X
  27532. X
  27533. X
  27534. *-*-END-of-doc/catmail.nr-*-*
  27535. echo x - doc/farch.nr
  27536. sed 's/^X//' >doc/farch.nr <<'*-*-END-of-doc/farch.nr-*-*'
  27537. X
  27538. X
  27539. X
  27540. Xfarch(1)                 USER COMMANDS                   farch(1)
  27541. X
  27542. X
  27543. X
  27544. XNNNNAAAAMMMMEEEE
  27545. X     ffffaaaarrrrcccchhhh - archive files under the ListProcessor system
  27546. X
  27547. XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
  27548. X     ffffaaaarrrrcccchhhh {[----nnnn] [----bbbb | ----BBBB] [----ssss ssssiiiizzzzeeee]  [----dddd ddddiiiirrrr]  [----pppp ppppaaaasssssssswwwwoooorrrrdddd]  [----
  27549. X     DDDD ddddeeeessssccccrrrriiiippppttttiiiioooonnnn] [----tttt ffffiiiilllleeee]  [-u]} | {[----rrrr]} [----aaaa aaaarrrrcccchhhhiiiivvvveeee |||| ppppaaaatttthhhh----
  27550. X     ttttoooo----aaaarrrrcccchhhhiiiivvvveeee] [----ZZZZ] <ffffiiiilllleeeessss>
  27551. X
  27552. XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
  27553. X     _f_a_r_c_h is used to archive files under the ListProcessor  sys-
  27554. X     tem  or  remove files already achived, with support provided
  27555. X     for    private    archives.     Archives    reside     under
  27556. X     HOMEDIR/archives as subdirectories; the default is _l_i_s_t_p_r_o_c,
  27557. X     and it is also the master archive. Archives  are  hierarchi-
  27558. X     cally structured, and each archive has at least two files in
  27559. X     its directory:
  27560. X
  27561. X     INDEX
  27562. X          A list of all subarchives including itself; the  format
  27563. X          is  one  line  per archive with the archive's name fol-
  27564. X          lowed by  the  archive's  full  path,  followed  by  an
  27565. X          optional password:
  27566. X
  27567. X          archive-name full-path-to-archive-directory [password]
  27568. X
  27569. X          The first entry should  be  the  archive  itself;  each
  27570. X          first level subarchive is listed next; then each second
  27571. X          level subarchive, starting with the first  first-level-
  27572. X          archive's  subarchives,  followed  by the second first-
  27573. X          level-archive's subarchives, etc. No  sibling  archives
  27574. X          may  have the same name, although there is no such res-
  27575. X          triction for archives on different levels, or  "cousin"
  27576. X          archives.  The latter archives are distinguished by the
  27577. X          relative path needed to access them (see _s_e_r_v_e_r(1)  for
  27578. X          more information).
  27579. X
  27580. X     DIR  A list of files available from that archive; the format
  27581. X          is one line per file with the file name followed by the
  27582. X          number of parts it may be split into, followed  by  the
  27583. X          number  of  bytes of each of the parts, followed by the
  27584. X          full path to the directory these parts  can  be  found,
  27585. X          followed  by a short descriptive message about the file
  27586. X          (optional). The descriptive message  may  span  several
  27587. X          lines;  each  line  (except the last) should end with a
  27588. X          '\':
  27589. X
  27590. X          file nparts size-of-each-part+ full-path-to-directory [description [\]]
  27591. X          [multiple description lines [\]]*
  27592. X
  27593. X          The number of parts the file is split into may be -1 to
  27594. X          indicate that this is a binary file.
  27595. X
  27596. X
  27597. X
  27598. X
  27599. XKubota Computer                                                 1
  27600. X
  27601. X
  27602. X
  27603. X
  27604. X
  27605. X
  27606. Xfarch(1)                 USER COMMANDS                   farch(1)
  27607. X
  27608. X
  27609. X
  27610. X     _f_a_r_c_h reports on  the  action  taken  on  each  input  file:
  27611. X     whether  it  was  split (and how many parts), whether it was
  27612. X     uuencoded, whether all files have been tar'red into a single
  27613. X     one,  the  archive  this  file  was  archived under, and the
  27614. X     directory the output file(s) (if any) has/have been  placed.
  27615. X     It also reports when the input files are tarred.
  27616. X
  27617. XOOOOPPPPTTTTIIIIOOOONNNNSSSS
  27618. X     The following command line options are recognized:
  27619. X
  27620. X     -n   Do not split files when archiving them. The default  is
  27621. X          to split them with each part not larger than the speci-
  27622. X          fied size (see the -s option below).
  27623. X
  27624. X     -b   Input files  are  binary;  they  are  uuencoded  before
  27625. X          archived.
  27626. X
  27627. X     -B   Input files are binary; they are neither uuencoded  nor
  27628. X          split.
  27629. X
  27630. X     -s size
  27631. X          Specify the maximum _s_i_z_e in kilobytes of  each  of  the
  27632. X          subparts (default is 64).
  27633. X
  27634. X     -d dir
  27635. X          Specify the _d_i_rectory that the output files are  to  be
  27636. X          placed;  if  left  out,  it  defaults  to the specified
  27637. X          archive's directory (HOMEDIR/archives/listproc  if  the
  27638. X          archive  is  left  out as well).  If the directory (and
  27639. X          all of its subdirectories, if any) does not  exist,  it
  27640. X          will be created.
  27641. X
  27642. X     -p password
  27643. X          When a new archive is to be created, and  that  archive
  27644. X          is to be private, specify the access password.
  27645. X
  27646. X     -D description
  27647. X          Put  _d_e_s_c_r_i_p_t_i_o_n  (most  likely  surrounded  by  single
  27648. X          quotes)  in  the  DIR file as explanatory comment about
  27649. X          the archived file. This option does not make much sense
  27650. X          when archiving more than one file at the same time.
  27651. X
  27652. X     -t file
  27653. X          Input  files  are  tar'red  into  _f_i_l_e  which  is  then
  27654. X          archived  (the  -b  flag  is  automatically turned on).
  27655. X          Turning on the -B flag will prevent uuencoding  of  the
  27656. X          tar  file.  Note that whatever the path to _f_i_l_e may be,
  27657. X          it will be moved to the specified directory  as  speci-
  27658. X          fied by the -d flag.
  27659. X
  27660. X     -u   Update existing files  while  archiving;  preserve  the
  27661. X          current comment fields, unless -D is explicitly used.
  27662. X
  27663. X
  27664. X
  27665. XKubota Computer                                                 2
  27666. X
  27667. X
  27668. X
  27669. X
  27670. X
  27671. X
  27672. Xfarch(1)                 USER COMMANDS                   farch(1)
  27673. X
  27674. X
  27675. X
  27676. X     -r   Remove the specified file(s) from the specified archive
  27677. X          (see below), or the default one; it has higher priority
  27678. X          than all of the options above.
  27679. X
  27680. X     -a archive | path-to-archive
  27681. X          Specify the  _a_r_c_h_i_v_e  that  the  input  files  will  be
  27682. X          archived  under (default is listproc). Archives on dif-
  27683. X          ferent levels of the hierarchy may have the  same  name
  27684. X          and  in this case a _p_a_t_h-_t_o-_a_r_c_h_i_v_e may be specified to
  27685. X          distinguish between them; _p_a_t_h-_t_o-_a_r_c_h_i_v_e has the  form
  27686. X          _a_r_c_h_i_v_e[/_a_r_c_h_i_v_e[/_a_r_c_h_i_v_e...]]   (see  also _s_e_r_v_e_r(_1)).
  27687. X          If any of the archives in the path do not  exist,  they
  27688. X          will be created with the necessary files.
  27689. X
  27690. X     -Z   Turn off file compression.
  27691. X
  27692. X     File names in the DIR file have to be unique and _f_a_r_c_h  will
  27693. X     not archive duplicate files.
  27694. X
  27695. XAAAARRRRCCCCHHHHIIIIVVVVIIIINNNNGGGG AAAA FFFFIIIILLLLEEEE
  27696. X     _f_a_r_c_h by default splits the input files if necessary (or the
  27697. X     tar  file, if any), into files of maximum size as specified.
  27698. X     Each part will contain as many complete lines from the  ori-
  27699. X     ginal  input  file as possible, without exceeding the speci-
  27700. X     fied size. Binary files (including the tar file)  are  uuen-
  27701. X     coded  before  they  are  archived  unless  the -B option is
  27702. X     specified, and all archived files are compressed, if  possi-
  27703. X     ble.
  27704. X
  27705. XAAAADDDDDDDDIIIINNNNGGGG AAAA NNNNEEEEWWWW AAAARRRRCCCCHHHHIIIIVVVVEEEE
  27706. X     automatically
  27707. X          Simply specify the new archive as argument  to  the  -a
  27708. X          flag.  All necessary DIR and INDEX files as well as all
  27709. X          required directories will be created,  and  all  parent
  27710. X          archives will be updated.
  27711. X
  27712. X     by hand
  27713. X          Step 1
  27714. X
  27715. X          Create a directory under HOMEDIR/archives or  under  an
  27716. X          existing  archive's  directory (beware of the hierarchy
  27717. X          structure), naming the  directory  after  the  archive.
  27718. X          The  archive's name should be unique among its siblings
  27719. X          on that level in the hierarchy (besides, mkdir will not
  27720. X          let specify a name that already exists).
  27721. X
  27722. X          Step 2
  27723. X
  27724. X          Edit    the     master     archive's     index     file
  27725. X          (HOMEDIR/archives/listproc/INDEX)   and   add  the  new
  27726. X          archive along with its path (and optional  password  --
  27727. X          see below) at the proper place in the file, making sure
  27728. X
  27729. X
  27730. X
  27731. XKubota Computer                                                 3
  27732. X
  27733. X
  27734. X
  27735. X
  27736. X
  27737. X
  27738. Xfarch(1)                 USER COMMANDS                   farch(1)
  27739. X
  27740. X
  27741. X
  27742. X          you adhere to the rules about hierarchy outined  above.
  27743. X          The  first  line  of  every  INDEX  file  should be the
  27744. X          archive itself.  Also  edit  (add  to)  every  ancestor
  27745. X          archive's  INDEX  file,  if  the new archive is not the
  27746. X          default, again making  sure  you  adhere  to  the  same
  27747. X          rules.
  27748. X
  27749. X          Step 3
  27750. X
  27751. X          Create a new INDEX file in the new archive's  directory
  27752. X          and put an entry for itself.
  27753. X
  27754. X          Step 4
  27755. X
  27756. X          Create an empty DIR file in the  new  archive's  direc-
  27757. X          tory.
  27758. X
  27759. XPPPPRRRRIIIIVVVVAAAATTTTEEEE AAAARRRRCCCCHHHHIIIIVVVVEEEESSSS
  27760. X     Private archives are archives that require  a  password  for
  27761. X     obtaining indices and/or files from them. To make an archive
  27762. X     private, simply append a password  (case  does  not  matter)
  27763. X     after  its  full  path specification in every INDEX file the
  27764. X     archive is defined (its own plus all ancestors' -- the  same
  27765. X     password  has  to be used in all of these files). Then, that
  27766. X     password has to be made known to all users  who  are  to  be
  27767. X     granted  access to this archive.  Note that all files in the
  27768. X     same private archive can be obtained with  the  same  single
  27769. X     password.
  27770. X
  27771. XEEEEXXXXAAAAMMMMPPPPLLLLEEEESSSS
  27772. X     Archive src/data and src/data2 under archive  listproc  (the
  27773. X     default),  using  a  maximum  file  size  of  1K; the output
  27774. X     file(s) will be placed in /tmp/tmp:
  27775. X
  27776. X       % farch -s 1 -d /tmp/tmp src/data src/data2
  27777. X
  27778. X     Archive   /etc/hosts   under   archive   unix    (that    is
  27779. X     listproc/unix) -- the -n flag is used to avoid writing split
  27780. X     parts to /etc which is doomed to fail:
  27781. X
  27782. X       % farch -n -a unix -d /etc -p private /etc/hosts
  27783. X
  27784. X     Archive  /etc/password  under  archive  pub/unix  (that   is
  27785. X     listproc/pub/unix):
  27786. X
  27787. X       % farch -n -a pub/unix -d /etc /etc/passwd
  27788. X
  27789. X     Tar and archive all files in /usr/src to the default archive
  27790. X     and place the tar file under /tmp/tmp:
  27791. X
  27792. X       % farch -t HOMEDIR/source -d /tmp/tmp /usr/src/*.c
  27793. X
  27794. X
  27795. X
  27796. X
  27797. XKubota Computer                                                 4
  27798. X
  27799. X
  27800. X
  27801. X
  27802. X
  27803. X
  27804. Xfarch(1)                 USER COMMANDS                   farch(1)
  27805. X
  27806. X
  27807. X
  27808. X     Descriptive messages about these files  are  added  manually
  27809. X     into  the  archive's DIR file. However, the -D option can be
  27810. X     used to specify a string as follows:
  27811. X
  27812. X       % farch -D 'ListProcessor system files' -t ulistproc.tar -n -d /usr/server /usr/server/*
  27813. X
  27814. XUUUUPPPPGGGGRRRRAAAADDDDIIIINNNNGGGG
  27815. X     If you are upgrading from:
  27816. X
  27817. X     5.5  The -B, -p, -r and -D options are new; functionality is
  27818. X          the same.
  27819. X
  27820. X     5.41 or less
  27821. X          Every DIR file should now include the size of  each  of
  27822. X          the  parts  of every file, placed between the number of
  27823. X          parts and the path name.
  27824. X
  27825. X          The -a option has been  extended  to  accept  paths  to
  27826. X          archives.
  27827. X
  27828. XRRRREEEESSSSTTTTRRRRIIIICCCCTTTTIIIIOOOONNNNSSSS
  27829. X     - Archive names and input files must  use  only  lower  case
  27830. X     characters of the alphabet.
  27831. X
  27832. XWWWWAAAARRRRNNNNIIIINNNNGGGGSSSS
  27833. X     - Input files that are to be  tar'red  should  only  include
  27834. X     relative  path names; otherwise the end user may not be able
  27835. X     to extract them.
  27836. X
  27837. X     - The tar file should not be any of the input files.
  27838. X
  27839. XSSSSEEEEEEEE AAAALLLLSSSSOOOO
  27840. X     server(1)
  27841. X
  27842. XAAAAUUUUTTTTHHHHOOOORRRR
  27843. X     Anastasios C. Kotsikonas
  27844. X     Copyright (c) 1991-93, Anastasios Kotsikonas
  27845. X     Comments to tasos@cs.bu.edu
  27846. X
  27847. X
  27848. X
  27849. X
  27850. X
  27851. X
  27852. X
  27853. X
  27854. X
  27855. X
  27856. X
  27857. X
  27858. X
  27859. X
  27860. X
  27861. X
  27862. X
  27863. XKubota Computer                                                 5
  27864. X
  27865. X
  27866. X
  27867. *-*-END-of-doc/farch.nr-*-*
  27868. echo x - doc/ilp.nr
  27869. sed 's/^X//' >doc/ilp.nr <<'*-*-END-of-doc/ilp.nr-*-*'
  27870. X
  27871. X
  27872. X
  27873. Xilp(1)                   USER COMMANDS                     ilp(1)
  27874. X
  27875. X
  27876. X
  27877. XNNNNAAAAMMMMEEEE
  27878. X     iiiillllpppp - Interactive ListProcessor client
  27879. X
  27880. XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
  27881. X     iiiillllpppp [----vvvv] [----tttt ttttiiiimmmmeeeeoooouuuutttt] [----bbbb bbbbuuuuffffffffeeeerrrr----ssssiiiizzzzeeee iiiinnnn KKKK] hhhhoooosssstttt [ppppoooorrrrtttt]
  27882. X
  27883. XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
  27884. X     _i_l_p is a  client  that  connects  to  the  specified  _h_o_s_t's
  27885. X     Interactive  ListProcessor  port (372) for a live session --
  27886. X     i.e. for processing  requests  live.  Another  _p_o_r_t  may  be
  27887. X     specified  if  necessary. The _h_o_s_t may be a host name, or an
  27888. X     IP address.
  27889. X
  27890. X     Upon connection establishment, the protocol attempts to  set
  27891. X     the  user's  privileges  during the session by requesting an
  27892. X     email address and a password.  These are used  to  determine
  27893. X     whether  the user is to be granted system, owner, subscriber
  27894. X     or casual user privileges. If the user  provides  his  owner
  27895. X     email  address  and  his list's password, he will be granted
  27896. X     owner privileges. If he provides an email  address  that  he
  27897. X     uses  for subscription to a list, along with the password he
  27898. X     uses  for  that  list,  he  will   be   granted   subscriber
  27899. X     privileges. The system provides a brief listing of all valid
  27900. X     requests the user may issue during the session. If no  email
  27901. X     address  is  provided,  or no matches are found, the user is
  27902. X     restricted to a few requests.
  27903. X
  27904. X     Requests for remote lists are serviced by attempting to con-
  27905. X     nect  to  the  ILP  server(s) (if any) of the system(s) that
  27906. X     handle those lists.
  27907. X
  27908. X     The ILP server recognizes the following special requests:
  27909. X
  27910. X     quit/exit
  27911. X          End the session.
  27912. X
  27913. X     ?/privileges
  27914. X          Get a brief listing of all valid requests.
  27915. X
  27916. X     timeleft
  27917. X          Prints the remaining time in seconds.
  27918. X
  27919. X     &<new-line>
  27920. X          Input continues on the next line.
  27921. X
  27922. X     binary
  27923. X          Switch to binary mode when transferring files.
  27924. X
  27925. X     ascii
  27926. X          Switch to ASCII mode when transferring files.
  27927. X
  27928. X     < filename
  27929. X
  27930. X
  27931. X
  27932. XKubota Computer                                                 1
  27933. X
  27934. X
  27935. X
  27936. X
  27937. X
  27938. X
  27939. Xilp(1)                   USER COMMANDS                     ilp(1)
  27940. X
  27941. X
  27942. X
  27943. X          Input is taken from the specified file. Each line  will
  27944. X          be  interpreted  as a separate request, unless the file
  27945. X          is specified in conjunction with a _p_u_t request. If  the
  27946. X          '<' is to be used literally it must be escaped with '\'
  27947. X          or enclosed in quotes.
  27948. X
  27949. X     > filename
  27950. X          Redirect the reply to  the  request  to  the  specified
  27951. X          file. Error messages (such as rejections due to invalid
  27952. X          requests, etc.) are not redirected.   When  a  file  is
  27953. X          downloaded  via  a  _g_e_t request, this will override the
  27954. X          file name that will be saved under. If the '>' is to be
  27955. X          used literally it must be escaped with \ or enclosed in
  27956. X          quotes.
  27957. X
  27958. X     >> filename
  27959. X          Same as above, but the reply is appended to the  speci-
  27960. X          fied file.
  27961. X
  27962. X     | prog [args]
  27963. X          The output of the request is piped  to  _p_r_o_g;  this  is
  27964. X          similar to a UNIX pipe. _p_r_o_g may be any valid UNIX com-
  27965. X          mand, including other pipes,  file  redirections,  etc.
  27966. X          Since  '<'  has  higher precedence in this context, you
  27967. X          should escape any '<' characters intended to be used by
  27968. X          the  pipe,  otherwise  the  system  will assume you are
  27969. X          feeding it batched requests. Quotes may also be used to
  27970. X          protect these characters.
  27971. X
  27972. XOOOOPPPPTTTTIIIIOOOONNNNSSSS
  27973. X     The following options are recognized:
  27974. X
  27975. X     -v   Turn verbose mode on; the server reply codes are echoed
  27976. X          along with predetermined messages.
  27977. X
  27978. X     -t timeout
  27979. X          The default time out  for  a  server  response  is  180
  27980. X          seconds;  to reset use the -t flag. This timeout should
  27981. X          not be confused with the remaining time  of  a  connec-
  27982. X          tion.
  27983. X
  27984. X     -b buffer-size
  27985. X          The default socket buffer size is 8K; to reset use  the
  27986. X          -b flag (the argument specifies kilobytes).
  27987. X
  27988. X
  27989. XUUUUSSSSEEEERRRR PPPPRRRRIIIIVVVVIIIILLLLEEEEGGGGEEEESSSS
  27990. X     Casual users may only issue  help,  information,  recipients
  27991. X     and  statistics  for  nonprivate  lists,  lists, index, get,
  27992. X     view, search and release  requests.   Subscriber  privileges
  27993. X     also  include  the set, run, unsubscribe and which requests.
  27994. X     Owners may, in addition, issue all of  their  administrative
  27995. X
  27996. X
  27997. X
  27998. XKubota Computer                                                 2
  27999. X
  28000. X
  28001. X
  28002. X
  28003. X
  28004. X
  28005. Xilp(1)                   USER COMMANDS                     ilp(1)
  28006. X
  28007. X
  28008. X
  28009. X     requests.
  28010. X
  28011. X     Issue a 'help live' request when you first connect to an ILP
  28012. X     server.
  28013. X
  28014. XRRRREEEESSSSTTTTRRRRIIIICCCCTTTTIIIIOOOONNNNSSSS
  28015. X     The connection  duration  is  limited  to  a  server-imposed
  28016. X     limit.  After that, a connection may be broken by the server
  28017. X     as necessary.  A connection will  not  be  broken  during  a
  28018. X     transfer.
  28019. X
  28020. XEEEEXXXXAAAAMMMMPPPPLLLLEEEESSSS
  28021. X     request> put ermis ermis1 subscribers </usr/server/backup/lists/ERMIS/subs >out
  28022. X
  28023. X     request> get listproc example.dat 1 3 >> out
  28024. X
  28025. X     request> get listproc example.dat
  28026. X
  28027. X     request> index ilp > ILP
  28028. X
  28029. X     request> < /tmp/batched.requests
  28030. X
  28031. X     request> index | more
  28032. X
  28033. X     request> lists | cut -d ' ' -f1,2 | more
  28034. X
  28035. X     request> search ilp "\>\> out"
  28036. X
  28037. X     In this last example, we escape each > to  protect  it  from
  28038. X     being  interpreted  as  a  regular expression separator, and
  28039. X     enclose the whole pattern in quotes to protect the \>\> from
  28040. X     being evaluated.
  28041. X
  28042. XFFFFIIIILLLLEEEESSSS
  28043. X     ilp.c, ilp.h
  28044. X          Source code for  the  client.  See  ilp.c  for  compile
  28045. X          options.
  28046. X
  28047. X     ilpp.h
  28048. X          Definition of the Interactive ListProcessor Protocol.
  28049. X
  28050. X     makefile
  28051. X          makefile to build _i_l_p. _i_l_p is  written  with  BSD-style
  28052. X          signal handling, therefore on some hosts (like IBM AIX)
  28053. X          you will have to link with BSD versions  of  signal(2),
  28054. X          socket(3N),  and  fcntl(2).  Platforms  that  have  the
  28055. X          <sys/select.h> and <ulimit.h> header files should  com-
  28056. X          pile  with  -DHAVE_SELECT_H and/or -DHAVE_ULIMIT_H. SCO
  28057. X          ports should  compile  with  -Dsco.  Always  link  with
  28058. X          libraries  that  provide  DNS  support (resolver linked
  28059. X          in).
  28060. X
  28061. X
  28062. X
  28063. X
  28064. XKubota Computer                                                 3
  28065. X
  28066. X
  28067. X
  28068. X
  28069. X
  28070. X
  28071. Xilp(1)                   USER COMMANDS                     ilp(1)
  28072. X
  28073. X
  28074. X
  28075. XBBBBUUUUGGGGSSSS
  28076. X     Please report any bugs or enhancements to tasos@cs.bu.edu
  28077. X
  28078. X
  28079. X
  28080. X
  28081. X
  28082. X
  28083. X
  28084. X
  28085. X
  28086. X
  28087. X
  28088. X
  28089. X
  28090. X
  28091. X
  28092. X
  28093. X
  28094. X
  28095. X
  28096. X
  28097. X
  28098. X
  28099. X
  28100. X
  28101. X
  28102. X
  28103. X
  28104. X
  28105. X
  28106. X
  28107. X
  28108. X
  28109. X
  28110. X
  28111. X
  28112. X
  28113. X
  28114. X
  28115. X
  28116. X
  28117. X
  28118. X
  28119. X
  28120. X
  28121. X
  28122. X
  28123. X
  28124. X
  28125. X
  28126. X
  28127. X
  28128. X
  28129. X
  28130. XKubota Computer                                                 4
  28131. X
  28132. X
  28133. X
  28134. *-*-END-of-doc/ilp.nr-*-*
  28135. echo x - doc/list.nr
  28136. sed 's/^X//' >doc/list.nr <<'*-*-END-of-doc/list.nr-*-*'
  28137. X
  28138. X
  28139. X
  28140. Xlist(1)                  USER COMMANDS                    list(1)
  28141. X
  28142. X
  28143. X
  28144. XNNNNAAAAMMMMEEEE
  28145. X     lllliiiisssstttt - process a specified ListProcessor mailing list
  28146. X
  28147. XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
  28148. X     lllliiiisssstttt ----LLLL <LLLLIIIISSSSTTTT____AAAALLLLIIIIAAAASSSS> [----1111] [----eeee] [----ssss] [----pppp]  [----PPPP]  [----mmmm ####]  [----ffff]
  28149. X     [----rrrr] [----MMMM] [----dddd] [----iiii <aaaaddddddddrrrreeeessssssss>] [----vvvv] [----ZZZZ] [----DDDD]
  28150. X
  28151. XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN::::
  28152. X     _l_i_s_t distributes the  message(s)  sent  to  _l_i_s_t__a_l_i_a_s@_y_o_u_r-
  28153. X     _d_o_m_a_i_n;  the  file  ".ignored" in the list's subdirectory is
  28154. X     used to filter out any unwanted messages (see below).
  28155. X
  28156. X     Messages from mailer daemons are  forwarded  to  the  list's
  28157. X     owner  and  screened  looking  for delivery errors (in which
  28158. X     case appropriate action is taken -- users are either immedi-
  28159. X     ately  removed  from the list, or after a series of delivery
  28160. X     errors within a certain time frame -- entries  removed  from
  28161. X     the       system's      files      are      placed      into
  28162. X     HOMEDIR/lists/*/removed.users                            and
  28163. X     HOMEDIR/lists/*/removed.alias  files), whereas messages from
  28164. X     non-subscribers are returned to the original senders (the -f
  28165. X     flag overrides this). Messages whose first line looks like a
  28166. X     ListProcessor request are bounced back to the sender.
  28167. X
  28168. X     Messages from news groups are distributed only to local sub-
  28169. X     scribers and peer lists. Messages from peers are distributed
  28170. X     to local subscribers and possibly  posted  to  news  groups.
  28171. X     Finally,  messages from local subscribers are either distri-
  28172. X     buted locally, copies are sent to all peers, and are  possi-
  28173. X     bly  posted  to  news groups, or are forwarded to the list's
  28174. X     owner for screening if the list is moderated.
  28175. X
  28176. X     All distributed messages (i.e. legitimate messages from sub-
  28177. X     scribers,  peers and news groups -- not rejected, ignored or
  28178. X     error    messages)    are    automatically    archived    in
  28179. X     HOMEDIR/lists/*/archive.     In    contrast,    the    files
  28180. X     HOMEDIR/lists/*/mbox contain  all  messages  sent  to  these
  28181. X     lists (including, error, rejected and ignored messages).
  28182. X
  28183. X     Email from one or more subscribers may be  selectively  dis-
  28184. X     tributed  to an alternate list of recipients, by way of res-
  28185. X     tricted mail (see below), in which case  mail  will  not  be
  28186. X     distributed to the regular subscribers.
  28187. X
  28188. X     When the system is for some reason aborted  while  making  a
  28189. X     delivery,  a built-in mechanism allows it to resume from the
  28190. X     point it left off.
  28191. X
  28192. XOOOOPPPPTTTTIIIIOOOONNNNSSSS
  28193. X     The following command line options are recognized:
  28194. X
  28195. X     -L LIST_ALIAS
  28196. X
  28197. X
  28198. X
  28199. XKubota Computer                                                 1
  28200. X
  28201. X
  28202. X
  28203. X
  28204. X
  28205. X
  28206. Xlist(1)                  USER COMMANDS                    list(1)
  28207. X
  28208. X
  28209. X
  28210. X          Process  any  messages  sent  to  this  _L_I_S_T__A_L_I_A_S   --
  28211. X          _L_I_S_T__A_L_I_A_S should be in capital letters.
  28212. X
  28213. X     -1   Execute only once; process the mailing list and  return
  28214. X          control  to  _s_e_r_v_e_r_d(1); any new messages that may have
  28215. X          arrived in the meantime will be processed  at  a  later
  28216. X          time.  Without  this option, _l_i_s_t will be listening for
  28217. X          messages for the specified list  for  ever.  _s_e_r_v_e_r_d(1)
  28218. X          uses this option by default when spawning _l_i_s_t.
  28219. X
  28220. X     -e   Echo reports to the screen; it has  no  effect  if  the
  28221. X          system has been compiled with -DSYSLOG.
  28222. X
  28223. X     -s   By default, only subscribers can  send  messages  to  a
  28224. X          list. This option turns off subscription checking.
  28225. X
  28226. X     -p   By default, replies to messages posted to  news  groups
  28227. X          go  to  the list; this option forces replies to be for-
  28228. X          warded to the original author.
  28229. X
  28230. X     -P   By default, replies to messages sent to subscribers and
  28231. X          peers  go to the list; this option forces replies to be
  28232. X          forwarded to the original author.
  28233. X
  28234. X     -m number
  28235. X          Normally, each outgoing message has one recipient. This
  28236. X          flag  switches to multi-recipient outgoing messages and
  28237. X          specifies the _n_u_m_b_e_r of recipients to  be  included  in
  28238. X          these messages.
  28239. X
  28240. X     -f   Forward any messages from non-subscribers to the list's
  28241. X          owner. By default, they are returned to the sender.
  28242. X
  28243. X     -r   Restricted mail: _l_i_s_t will look  at  the  ".restricted"
  28244. X          file (see below) to get the name of the alternate reci-
  28245. X          pients file. If the sender is  listed  in  that  ".res-
  28246. X          tricted"  file,  his  messages  will  be distributed to
  28247. X          users listed in the alternate recipients file.
  28248. X
  28249. X     -M   The list is moderated; all incoming messages  not  from
  28250. X          the  owner(s) are forwarded to the list's primary owner
  28251. X          for review and editing. The owner then sends  back  the
  28252. X          ones  that  are  approved for posting (for an alternate
  28253. X          scheme see the MODERATED LISTS section below).
  28254. X
  28255. X     -d   Force a digest to be distributed. This flag  is  inter-
  28256. X          nally  used  by  _s_e_r_v_e_r_d(1)  when  digest time has been
  28257. X          reached for this list.
  28258. X
  28259. X     -i address
  28260. X          Send a partial digest to _a_d_d_r_e_s_s (what has  accumulated
  28261. X          so  far).   This flag is internally used by _l_i_s_t_p_r_o_c(1)
  28262. X
  28263. X
  28264. X
  28265. XKubota Computer                                                 2
  28266. X
  28267. X
  28268. X
  28269. X
  28270. X
  28271. X
  28272. Xlist(1)                  USER COMMANDS                    list(1)
  28273. X
  28274. X
  28275. X
  28276. X          when the user identified by _a_d_d_r_e_s_s  changes  his  _m_a_i_l
  28277. X          mode  from _d_i_g_e_s_t to something else. Note that when the
  28278. X          time arrives for the current digest to be  distributed,
  28279. X          this user will get duplicate messages.
  28280. X
  28281. X     -v   Print version information.
  28282. X
  28283. X     -Z   Turn off file compression when archiving messages.
  28284. X
  28285. X     -D   Turns debugging on. When the _s_y_s_t_e_m mailmethod is  used
  28286. X          (see  _s_e_r_v_e_r(_1)),  a  copy of the last SMTP transaction
  28287. X          can  be   found   in   the   files   HOMEDIR/sent   and
  28288. X          HOMEDIR/received.
  28289. X
  28290. XAAAADDDDDDDDIIIINNNNGGGG AAAA NNNNEEEEWWWW LLLLIIIISSSSTTTT
  28291. X     To add a new list, first shut the system down  by  executing
  28292. X     _s_t_a_r_t(1):
  28293. X
  28294. X       % _s_t_a_r_t -_k
  28295. X
  28296. X     Then edit the _c_o_n_f_i_g file and add a line  defining  the  new
  28297. X     list  --  you may wish to add a comment and/or disable a few
  28298. X     requests  also.   A  new  alias  has  to  be   set   up   in
  28299. X     /etc/aliases, /usr/lib/aliases or /usr/ucblib/aliases of the
  28300. X     following form:
  28301. X
  28302. X     list_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f"
  28303. X
  28304. X     If using surrogate mail, then the alias is defined  as  fol-
  28305. X     lows in /etc/mail/mailsurr:
  28306. X
  28307. X     '.+' 'list_alias' '<S=0;F=1-255;C=*;HOMEDIR/catmail -L LIST_ALIAS -f'
  28308. X
  28309. X     Note that _l_i_s_t__a_l_i_a_s is all lower case and _L_I_S_T__A_L_I_A_S is all
  28310. X     upper case. In this case _c_a_t_m_a_i_l(1) appends incoming mail to
  28311. X     the list's mail file (HOMEDIR/lists/LIST_ALIAS/mail).   Also
  28312. X     keep  in mind the case of reformatting messages as described
  28313. X     in _c_a_t_m_a_i_l(1).
  28314. X
  28315. X     Finally,  restart  the  system.  At  this  point,  the  file
  28316. X     ".ignored"  in the HOMEDIR/lists/LIST_ALIAS directory may be
  28317. X     edited to add more unwanted senders. You  should  also  edit
  28318. X     the files ".welcome" and ".info" in the list's subdirectory;
  28319. X     the former is included in the return message for a new  sub-
  28320. X     scription  request for that list, and the latter is included
  28321. X     in the return message for an _i_n_f_o_r_m_a_t_i_o_n  request  for  that
  28322. X     list  (see  _l_i_s_t_p_r_o_c(1)).  These  files  may  be simple text
  28323. X     files, or shell scripts (see the HELP section in _s_e_r_v_e_r(_1)).
  28324. X
  28325. XAAAADDDDDDDDIIIINNNNGGGG AAAA PPPPEEEEEEEERRRR LLLLIIIISSSSTTTT
  28326. X     Peer lists are mailing lists that happen to  be  subscribers
  28327. X     to  one or more of your own mailing lists; they handle local
  28328. X
  28329. X
  28330. X
  28331. XKubota Computer                                                 3
  28332. X
  28333. X
  28334. X
  28335. X
  28336. X
  28337. X
  28338. Xlist(1)                  USER COMMANDS                    list(1)
  28339. X
  28340. X
  28341. X
  28342. X     distribution of messages just like you do at your own  site.
  28343. X     Peer lists can be mutual subscribers, so that a message ori-
  28344. X     ginating in a peer list gets distributed over there locally,
  28345. X     and  a copy is sent to the other for local distribution, and
  28346. X     vice versa. An automatic mechanism is provided for  avoiding
  28347. X     loops.   A peer list can be added to a local mailing list by
  28348. X     using the script _p_e_e_r:
  28349. X
  28350. X     peer <LIST_ALIAS> <remote alias> <peer address> <remote ListProcessor address>
  28351. X
  28352. X     where  _L_I_S_T__A_L_I_A_S  is a local list alias in capital letters,
  28353. X     _r_e_m_o_t_e _a_l_i_a_s is the peer's  alias  on  the  remote  machine,
  28354. X     _p_e_e_r _a_d_d_r_e_s_s is taken from the first line of the header of a
  28355. X     test message sent to your host by the peer (the  first  line
  28356. X     may  be something like: "From peer@other-domain" -- see also
  28357. X     the     discussion     about     aliases     below),     and
  28358. X     _r_e_m_o_t_e _L_i_s_t_P_r_o_c_e_s_s_o_r _a_d_d_r_e_s_s  is  the  full email address of
  28359. X     the remote request-handler.
  28360. X
  28361. X     Here is an example for establishing connection  between  two
  28362. X     peer  lists a@domain1 and b@domain2:  The _m_a_n_a_g_e_r at domain1
  28363. X     issues the following command:
  28364. X
  28365. X     peer a b b@domain2 listproc@hdomain2
  28366. X
  28367. X     The _m_a_n_a_g_e_r at domain2 issues the following command:
  28368. X
  28369. X     peer b a a@domain1 listproc@domain1
  28370. X
  28371. X     Once  these  two  commands  are  issued  the  connection  is
  28372. X     automatically set up.  Peer lists should make sure that only
  28373. X     one of them posts to the same news group(s), and  that  only
  28374. X     one   of   them   receives   articles  from  the  same  news
  28375. X     group(s)/gateway(s).  Lists handled by the same server  can-
  28376. X     not be mutual peers. Finally, peer lists should not be regu-
  28377. X     lar subscribers (the _p_e_e_r  script  places  them  in  a  file
  28378. X     called ".peers").
  28379. X
  28380. XNNNNEEEEWWWWSSSS GGGGRRRROOOOUUUUPPPPSSSS AAAANNNNDDDD GGGGAAAATTTTEEEEWWWWAAAAYYYYSSSS
  28381. X     A mailing list may be linked with one or  more  news  groups
  28382. X     (or  gateways)  from which it may receive messages for local
  28383. X     distribution, and/or send messages to the  newsgroup(s)  for
  28384. X     posting  --  in  this  case  only messages from regular sub-
  28385. X     scribers and peers are sent for posting, i.e. no  news  mes-
  28386. X     sages  will  be  posted  to any news groups (or gateways). A
  28387. X     news group or gateway is linked using the script _n_e_w_s:
  28388. X
  28389. X        news <LIST_ALIAS> <news group> <email address> <mode>
  28390. X
  28391. X     where _L_I_S_T__A_L_I_A_S is a local list alias (in capital  letters)
  28392. X     that  is  being  linked to the news group, _n_e_w_s _g_r_o_u_p is the
  28393. X     name of  the  news  group  (used  only  when  posting)  e.g.
  28394. X
  28395. X
  28396. X
  28397. XKubota Computer                                                 4
  28398. X
  28399. X
  28400. X
  28401. X
  28402. X
  28403. X
  28404. Xlist(1)                  USER COMMANDS                    list(1)
  28405. X
  28406. X
  28407. X
  28408. X     misc.test,  _e_m_a_i_l _a_d_d_r_e_s_s  is the address of the backbone or
  28409. X     moderator of the news group, or the gateway, and it is taken
  28410. X     from  the first line of the header of a test message sent to
  28411. X     your host by the group (the  first  line  may  be  something
  28412. X     like:  "From  gateway@foo  ..."  --  see also the discussion
  28413. X     about aliases below); _m_o_d_e is one of the following:
  28414. X
  28415. X     receive
  28416. X          The list will only be receiving messages from this news
  28417. X          group  and  never post to it. This allows access to the
  28418. X          group (or gateway) to send articles to the list.
  28419. X
  28420. X     send_receive
  28421. X          The list may  be  receiving  messages  from  this  news
  28422. X          group, and it will post to it any messages from regular
  28423. X          subscribers and peer lists (messages from  news  groups
  28424. X          are  never  posted  to  other  news  groups). This also
  28425. X          allows access to the group (or gateway) to  send  arti-
  28426. X          cles to the list.
  28427. X
  28428. X     Of course, the news group's caretaker has to be notified  of
  28429. X     the  list's  address so that articles will indeed be sent to
  28430. X     it. Finally, news groups should not be  regular  subscribers
  28431. X     (the _n_e_w_s script places them in a file called ".news").
  28432. X
  28433. X     If the config option _p_o_s_t__m_a_i_l is used, the system will  use
  28434. X     _i_n_e_w_s  for  posting,  and  it assumes that the path to it is
  28435. X     /usr/lib/news/inews, so make sure that _i_n_e_w_s resides  there,
  28436. X     or  a  link  exists to it. In this case, the group's name is
  28437. X     used for posting (e.g. misc.test). If instead  _g_a_t_e__m_a_i_l  is
  28438. X     defined,  messages  will  be sent via email to news gateways
  28439. X     (using the _e_m_a_i_l _a_d_d_r_e_s_s) -- the _n_e_w_s _g_r_o_u_p name has no sig-
  28440. X     nificance in this case.
  28441. X
  28442. XMMMMOOOODDDDEEEERRRRAAAATTTTEEEEDDDD LLLLIIIISSSSTTTTSSSS
  28443. X     The system supports two schemes for  moderating  lists.  The
  28444. X     first  scheme  uses the -M flag to _l_i_s_t(1), and in this case
  28445. X     messages not from the list's owner(s) are forwarded  to  the
  28446. X     list's  primary  owner for review; the owner then sends back
  28447. X     the approved (and possibly edited) ones.
  28448. X
  28449. X     The second scheme uses the -m flag to  _c_a_t_m_a_i_l(1).  In  this
  28450. X     case,  the  list's  alias is changed slightly in the aliases
  28451. X     file:
  28452. X
  28453. X     list_alias: "|HOMEDIR/catmail -L LIST_ALIAS -f -m"
  28454. X
  28455. X     and similarly if using surrogate mail.  _l_i_s_t(1)  distributes
  28456. X     messages  from  a  file called _m_a_i_l; by having incoming mes-
  28457. X     sages redirected to the file _m_o_d_e_r_a_t_e_d (the effect of the -m
  28458. X     flag to _c_a_t_m_a_i_l(1)), the list's owner may _a_p_p_r_o_v_e or _d_i_s_c_a_r_d
  28459. X     any number of these messages (see _l_i_s_t_p_r_o_c(1)).  Whenever  a
  28460. X
  28461. X
  28462. X
  28463. XKubota Computer                                                 5
  28464. X
  28465. X
  28466. X
  28467. X
  28468. X
  28469. X
  28470. Xlist(1)                  USER COMMANDS                    list(1)
  28471. X
  28472. X
  28473. X
  28474. X     new  mail  message  arrives  for a moderated list, a copy is
  28475. X     sent to the list's owner with instructions for approving  or
  28476. X     discarding  it.  These  instructions  include  a  unique tag
  28477. X     number for identifying  that  message.  When  a  message  is
  28478. X     approved,  it  is  transferred  to  the  _m_a_i_l file for later
  28479. X     delivery, and when discarded, it is simply removed from  the
  28480. X     _m_o_d_e_r_a_t_e_d file. This scheme cuts down on mail traffic.
  28481. X
  28482. XRRRREEEESSSSTTTTRRRRIIIICCCCTTTTEEEEDDDD MMMMAAAAIIIILLLL
  28483. X     When the -r flag is used with  _l_i_s_t(1),  for  every  message
  28484. X     received  its  sender  is  checked  against  a list of "res-
  28485. X     tricted" email addresses, in the file ".restricted"  in  the
  28486. X     list's  directory -- a subset of the ".subscribers" file. If
  28487. X     a match is found, mail is forwarded to the people listed  in
  28488. X     the file following this email address. If no match is found,
  28489. X     the message is distributed to the regular subscribers.  Note
  28490. X     that  the  alternate  recipients  file should be in the same
  28491. X     format as the ".subscribers".
  28492. X
  28493. X....SSSSUUUUBBBBSSSSCCCCRRRRIIIIBBBBEEEERRRRSSSS
  28494. X     The format is as follows:
  28495. X
  28496. X     One entry per line; each entry is the full email address  of
  28497. X     the  subscriber as it appears in the "From " field, followed
  28498. X     by the word "ACK" (in which case  his/her  message  will  be
  28499. X     sent  back  to  him/her as an acknowledgement), "NOACK" (the
  28500. X     opposite), "POSTPONE" (no mail will be sent until  the  user
  28501. X     changes  mode  again), or "DIGEST" (digests are periodically
  28502. X     sent), followed by a string  that  plays  the  role  of  the
  28503. X     user's  password, followed by either "YES" or "NO" which are
  28504. X     the  values  of  the  conceal  attribute,  followed  by  the
  28505. X     subscriber's name. See also _l_i_s_t_p_r_o_c(1).
  28506. X
  28507. X....RRRREEEESSSSTTTTRRRRIIIICCCCTTTTEEEEDDDD
  28508. X     The format is as follows:
  28509. X
  28510. X     One entry per line; each entry is the full email address  of
  28511. X     the   subscriber,  followed  by  a  file  name  where  email
  28512. X     addresses of recipients are listed (just like in the  ".sub-
  28513. X     scribers" file). Example:
  28514. X
  28515. X        jdoe@foo.bar.com  HOMEDIR/lists/LIST_ALIAS/.recipients
  28516. X
  28517. X     If the recipient file given is the word "NONE", then no  one
  28518. X     will receive any messages.
  28519. X
  28520. X....AAAALLLLIIIIAAAASSSSEEEESSSS
  28521. X     It   is    possible    that    a    subscriber's/peer's/news
  28522. X     group's/gateway's  email  may  arrive using a different path
  28523. X     than registered, which may  raise  subscription  issues.  To
  28524. X     work  around  this,  each list provides a ".aliases" file in
  28525. X     its  subdirectory,  which  may   contain   alternate   email
  28526. X
  28527. X
  28528. X
  28529. XKubota Computer                                                 6
  28530. X
  28531. X
  28532. X
  28533. X
  28534. X
  28535. X
  28536. Xlist(1)                  USER COMMANDS                    list(1)
  28537. X
  28538. X
  28539. X
  28540. X     addresses  to  be  used  when checking for subscription. The
  28541. X     format is one line per alias with the following information:
  28542. X
  28543. X                 alias-address address-as-subscribed
  28544. X
  28545. X     Please note that only the subscribed  address  is  used  for
  28546. X     sending  out  email  (see next section about regular expres-
  28547. X     sions).
  28548. X
  28549. X     The  aliased  address  may  be  a  regular  expression  with
  28550. X     egrep(1)  style  syntax, in which case the following charac-
  28551. X     ters have special meanings:  '~',  if  leading  the  regular
  28552. X     expression  it  reverses  its  meaning; '|' and '&' separate
  28553. X     multiple regular expressions (logical OR and AND);  '<'  '>'
  28554. X     group  regular  expressions  (we preserve the meaning of the
  28555. X     parentheses from ed(1), and remove the meaning of  <  and  >
  28556. X     from  ed(1)  since  in  the  ListProcessor  context they are
  28557. X     either the default, or inappropriate).  These  can  be  used
  28558. X     literally  by  escaping them with '\'. In addition, the fol-
  28559. X     lowing characters should be defined in  matched  pairs:  (),
  28560. X     <>, [], "". For example:
  28561. X
  28562. X                  jdoe@.*\.bar\.com jdoe@foo.bar.com
  28563. X
  28564. X     will enable this user to send messages from any  machine  in
  28565. X     his local network and receive replies at foo.bar.com -- keep
  28566. X     in mind that a '.'  matches exactly one character, and  '.*'
  28567. X     matches  zero  or  more  characters.   In a more complicated
  28568. X     example:
  28569. X
  28570. X           ~jdoe@cc.*|jdoe@....*\.bar\.com jdoe@foo.bar.com
  28571. X
  28572. X     will match if jdoe sends a message from a machine whose name
  28573. X     does  not  start with 'cc', or from a machine whose name has
  28574. X     at least 3 characters.
  28575. X
  28576. X     If   certain   parts   of   the   regular   expression   are
  28577. X     parenthesized,  then the strings that matched the subexpres-
  28578. X     sions can be used in the 'address-as-subscribed' to form new
  28579. X     return  addresses;  these matched strings are accessed by \_n
  28580. X     where _n is a digit between 1 and  9.  For  example,  if  the
  28581. X     sender is:
  28582. X
  28583. X                     GATE!HOP!USER@UUCP.SOME.COM
  28584. X
  28585. X     and the entry in the ".aliases" file reads:
  28586. X
  28587. X               [^!@]*!([^!@.]*)!([^!@]*)@.*  \2@\1.UUCP
  28588. X
  28589. X     then what will be returned as 'address-as-subscribed' is:
  28590. X
  28591. X                            USER@HOP.UUCP
  28592. X
  28593. X
  28594. X
  28595. XKubota Computer                                                 7
  28596. X
  28597. X
  28598. X
  28599. X
  28600. X
  28601. X
  28602. Xlist(1)                  USER COMMANDS                    list(1)
  28603. X
  28604. X
  28605. X
  28606. X     This way you can map addresses coming in via  various  gate-
  28607. X     ways  to  steady  ones  (\2  refers  to  the  second  set of
  28608. X     parentheses, and  \1  to  the  first).   Managers  may  edit
  28609. X     HOMEDIR/src/regex.c  to  test  regular  expression behavior,
  28610. X     introduce ls(1) style meanings to the * and ?  wild  charac-
  28611. X     ters,  undefine ed(1) special characters, and enforce strict
  28612. X     egrep(1) syntax (remove the meanings of ~ & < and >).
  28613. X
  28614. X     Regular expressions should be used with caution for  obvious
  28615. X     reasons.
  28616. X
  28617. X     If someone is experiencing subscription  problems,  you  may
  28618. X     wish  to add their alternate email address(es) in this file.
  28619. X     This includes regular subscribers, news  groups,  peers  and
  28620. X     gateways.  If the sender is also a restricted subscriber, do
  28621. X     not forget to put another entry in  ".restricted"  with  the
  28622. X     new  alternate address. Any number of aliases may be defined
  28623. X     for each individual address.
  28624. X
  28625. X     In addition, a ".aliases" file is also provided for ListPro-
  28626. X     cessor  requests  and  is  under HOMEDIR. The same syntax is
  28627. X     used, but each entry has a slightly different meaning:
  28628. X
  28629. X              address-as-arrived address-used-for-reply
  28630. X
  28631. X     In this case, _a_d_d_r_e_s_s-_u_s_e_d-_f_o_r-_r_e_p_l_y will be used  to  reply
  28632. X     to  all  requests  sent in by _a_d_d_r_e_s_s-_a_s-_a_r_r_i_v_e_d. A user may
  28633. X     have any number of aliases, but only the first one  matching
  28634. X     _a_d_d_r_e_s_s-_a_s-_a_r_r_i_v_e_d  will  be  used.  Like  before, the first
  28635. X     argument may be a regular expression and the second may  use
  28636. X     the matches in the first.
  28637. X
  28638. X     For each new list, the system  puts  the  following  default
  28639. X     alias in its ".aliases" file:
  28640. X
  28641. X                       ^@.*:(.*)@(.*\..*) \1@\2
  28642. X
  28643. X     This removes source routing.
  28644. X
  28645. X....IIIIGGGGNNNNOOOORRRREEEEDDDD
  28646. X     As described before, the system's home directory as well  as
  28647. X     every  list's  subdirectory contains a ".ignored" file which
  28648. X     is used to filter out messages sent by  certain  users.  The
  28649. X     default  file contains entries for server, bin, and sys; you
  28650. X     may wish to add an  entry  for  every  list  alias  that  is
  28651. X     defined  on  your system. A list's ".ignored" file also con-
  28652. X     tains an entry of its alias and full email address, as  well
  28653. X     as the server account's full email address.
  28654. X
  28655. X     Entries in this file may  also  be  regular  expressions  as
  28656. X     explained  in the previous section. For example, to restrict
  28657. X     requests (and postings) to .com and .edu  domain  addresses,
  28658. X
  28659. X
  28660. X
  28661. XKubota Computer                                                 8
  28662. X
  28663. X
  28664. X
  28665. X
  28666. X
  28667. X
  28668. Xlist(1)                  USER COMMANDS                    list(1)
  28669. X
  28670. X
  28671. X
  28672. X     one may add:
  28673. X
  28674. X                          ~<.*\.com|.*\.edu>
  28675. X
  28676. X     Notice, it is incorrect to list them as follows:
  28677. X
  28678. X                               ~.*\.com
  28679. X                               ~.*\.edu
  28680. X
  28681. X     as anything not from the .com domain matches the first regu-
  28682. X     lar  expression,  and  therefore will be ignored.  To refuse
  28683. X     access to certain user  names  and  certain  sites  one  may
  28684. X     include:
  28685. X
  28686. X                         .*\.bar\.com|jdoe@.*
  28687. X
  28688. X     The system's manager should use extra  caution  when  adding
  28689. X     regular expressions to the system's ".ignored" file, because
  28690. X     a simple '.*' prohibits anyone from using its services.
  28691. X
  28692. XSSSSEEEEEEEE AAAALLLLSSSSOOOO
  28693. X     catmail(1), listproc(1), server(1), serverd(1), start(1)
  28694. X
  28695. XAAAAUUUUTTTTHHHHOOOORRRR
  28696. X     Anastasios C. Kotsikonas
  28697. X     Copyright (c) 1991-93, Anastasios Kotsikonas
  28698. X     Comments to tasos@cs.bu.edu
  28699. X
  28700. X
  28701. X
  28702. X
  28703. X
  28704. X
  28705. X
  28706. X
  28707. X
  28708. X
  28709. X
  28710. X
  28711. X
  28712. X
  28713. X
  28714. X
  28715. X
  28716. X
  28717. X
  28718. X
  28719. X
  28720. X
  28721. X
  28722. X
  28723. X
  28724. X
  28725. X
  28726. X
  28727. XKubota Computer                                                 9
  28728. X
  28729. X
  28730. X
  28731. *-*-END-of-doc/list.nr-*-*
  28732. echo x - doc/listproc.nr
  28733. sed 's/^X//' >doc/listproc.nr <<'*-*-END-of-doc/listproc.nr-*-*'
  28734. X
  28735. X
  28736. X
  28737. Xlistproc(1)              USER COMMANDS                listproc(1)
  28738. X
  28739. X
  28740. X
  28741. XNNNNAAAAMMMMEEEE
  28742. X     lllliiiissssttttpppprrrroooocccc  -  process  requests  sent  to  the  ListProcessor
  28743. X     request handler
  28744. X
  28745. XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
  28746. X     lllliiiissssttttpppprrrroooocccc  [----1111]  [----eeee]  [----iiii]  [----nnnn]  {[----aaaa <LLLLIIIISSSSTTTT____AAAALLLLIIIIAAAASSSS>]}*   {[----
  28747. X     rrrr <rrrreeeeqqqq>]}* {[----dddd <rrrreeeeqqqq>]}* {[----bbbb <rrrreeeeqqqq>]}* [----BBBB] [----DDDD]
  28748. X
  28749. XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
  28750. X     _l_i_s_t_p_r_o_c processes  user  requests  sent  to  _l_i_s_t_p_r_o_c@_y_o_u_r-
  28751. X     _d_o_m_a_i_n,  forwards  requests  about  known  remote lists, and
  28752. X     processes list-owner administrative requests (see  also  the
  28753. X     LIST OWNERS section below).  Each request should appear in a
  28754. X     separate  line  with  any  possible  arguments.   The   file
  28755. X     ".ignored"  is used in the system's home directory to filter
  28756. X     out unwanted senders. If the system  is  not  instructed  to
  28757. X     ignore   invalid   requests   (see  the  CONFIG  section  in
  28758. X     _s_e_r_v_e_r(_1)), the sender is  notified  of  the  first  invalid
  28759. X     request; all subsequent requests are ignored.  For each suc-
  28760. X     cessfully completed request, a confirmation is sent back  to
  28761. X     the sender.
  28762. X
  28763. X     _l_i_s_t_p_r_o_c stops  reading  requests  when  it  encounters  the
  28764. X     string  "--" in a line by itself, which on most systems sig-
  28765. X     nifies the start of the .signature message, or at the  first
  28766. X     occurence  of  a thankful request. _l_i_s_t_p_r_o_c reads the _c_o_n_f_i_g
  28767. X     file (see _s_e_r_v_e_r(_1)).
  28768. X
  28769. X     Subscriptions may be manager-approved (private lists), files
  28770. X     and  archive  indices  may  be  password  protected (private
  28771. X     archives), and requests may be placed in a batch  queue.   A
  28772. X     single  request  may  span  multiple lines if each part ends
  28773. X     with &\_n.
  28774. X
  28775. XUUUUSSSSEEEERRRR RRRREEEEQQQQUUUUEEEESSSSTTTTSSSS
  28776. X     The following user requests are recognized (requests may  be
  28777. X     abbreviated):
  28778. X
  28779. X     _h_e_l_p [topic]
  28780. X          Send a help  message  on  all  valid  requests  or  the
  28781. X          selected topic (possibly a request) only.
  28782. X
  28783. X     _s_e_t list [option arg(s)]
  28784. X          Without the  optional  arguments,  return  the  current
  28785. X          values  for  all  options  set for _l_i_s_t; otherwise, set
  28786. X          subscriber preferences for _l_i_s_t.
  28787. X
  28788. X          _o_p_t_i_o_n can be:
  28789. X
  28790. X            _m_a_i_l: set mail preferences.
  28791. X
  28792. X              _a_r_g has to be one of the following:
  28793. X
  28794. X
  28795. X
  28796. XAnastasios Kotsikonas                                               1
  28797. X
  28798. X
  28799. X
  28800. X
  28801. X
  28802. X
  28803. Xlistproc(1)              USER COMMANDS                listproc(1)
  28804. X
  28805. X
  28806. X
  28807. X                _a_c_k: send a copy of the current  message  to  the
  28808. X                original sender.
  28809. X
  28810. X                _n_o_a_c_k: do not send a copy of the current  message
  28811. X                to  the original sender.  This is the default for
  28812. X                newly subscribed users.
  28813. X
  28814. X                _p_o_s_t_p_o_n_e: do not send any messages to the partic-
  28815. X                ular subscriber until he changes status again.
  28816. X
  28817. X                _d_i_g_e_s_t: do not send individual  messages  to  the
  28818. X                particular subscriber. Instead, store messages in
  28819. X                a digest and send it when the  digest  exceeds  a
  28820. X                specified  number  of  lines, or when a specified
  28821. X                amount of time has passed since the  last  digest
  28822. X                was sent.
  28823. X
  28824. X                If the mail mode is changed from _d_i_g_e_s_t  to  any-
  28825. X                thing else, all messages currently stored for the
  28826. X                next digest will be sent  to  the  subscriber  at
  28827. X                once, in digest format.
  28828. X
  28829. X            _p_a_s_s_w_o_r_d: change the password (used to establish sub-
  28830. X            scriber  privileges  when connecting to ListProcessor
  28831. X            for a "live" session and for the option below).
  28832. X
  28833. X              _a_r_g_s must be: old-password new-password.
  28834. X
  28835. X            _a_d_d_r_e_s_s: set the address the user is subscribed  with
  28836. X            (if allowed for this list).
  28837. X
  28838. X              _a_r_g_s must be: current-password new-address.
  28839. X
  28840. X            _c_o_n_c_e_a_l: set the user's visibility.
  28841. X
  28842. X              _a_r_g must be one of the following:
  28843. X
  28844. X                _y_e_s: the user is not  listed  in  _r_e_c_i_p_i_e_n_t_s  and
  28845. X                _s_t_a_t_i_s_t_i_c_s requests.
  28846. X
  28847. X                _n_o: the user's email address and  name  are  made
  28848. X                public.
  28849. X
  28850. X     _s_u_b_s_c_r_i_b_e list full_name
  28851. X          Subscribe the sender to _l_i_s_t (note, his  email  address
  28852. X          is  used  for subscription, not his _f_u_l_l__n_a_m_e). A pass-
  28853. X          word is assigned by the system  at  that  time  and  is
  28854. X          included  in  the  reply message to the new subscriber.
  28855. X          The password is to  be  used  when  connecting  to  the
  28856. X          interactive  part of the system for identification pur-
  28857. X          poses, and for changing  the  subscription  address  if
  28858. X          allowed for this list.
  28859. X
  28860. X
  28861. X
  28862. XAnastasios Kotsikonas                                               2
  28863. X
  28864. X
  28865. X
  28866. X
  28867. X
  28868. X
  28869. Xlistproc(1)              USER COMMANDS                listproc(1)
  28870. X
  28871. X
  28872. X
  28873. X     _w_h_i_c_h
  28874. X          Get a list of local mailing lists to which  the  sender
  28875. X          has subscribed.
  28876. X
  28877. X     _u_n_s_u_b_s_c_r_i_b_e list
  28878. X          Remove the sender from the specified _l_i_s_t.
  28879. X
  28880. X     _s_i_g_n_o_f_f list
  28881. X          Alias of the unsubscribe request.
  28882. X
  28883. X     _r_e_c_i_p_i_e_n_t_s list
  28884. X          Get a list of all subscribers of _l_i_s_t. The  request  is
  28885. X          also  forwarded to all peer lists, and the servers han-
  28886. X          dling them will respond accordingly.  The user is noti-
  28887. X          fied when this request is being forwarded. If a list is
  28888. X          private, only members may issue this request.
  28889. X
  28890. X     _r_e_v_i_e_w list
  28891. X          Alias of the recipients request.
  28892. X
  28893. X     _i_n_f_o_r_m_a_t_i_o_n list
  28894. X          Get information about a particular _l_i_s_t.
  28895. X
  28896. X     _s_t_a_t_i_s_t_i_c_s list {[subscriber email address(es)] | [-all]}
  28897. X          Obtain a count of messages sent per subscriber  to  the
  28898. X          specified  _l_i_s_t, or by those subscribers given as argu-
  28899. X          ment only (wild characters are supported). If  -_a_l_l  is
  28900. X          specified,  then  statistics are compiled for all users
  28901. X          (currently subscribed or not) who have  posted  to  the
  28902. X          list in the past.  The request is also forwarded to all
  28903. X          peer lists and the servers handling them  will  respond
  28904. X          accordingly.  The user is notified when this request is
  28905. X          being forwarded.  If a list is  private,  only  members
  28906. X          may issue this request.
  28907. X
  28908. X     _r_u_n list [password cmd [args]]
  28909. X          Without the optional arguments, just list all  commands
  28910. X          that  may be executed by subscribers of this _l_i_s_t. Oth-
  28911. X          erwise, run _c_m_d with the optional _a_r_g_s, if the  correct
  28912. X          _p_a_s_s_w_o_r_d is provided. The reply will contain the output
  28913. X          from stdout and/or stderr.
  28914. X
  28915. X     _l_i_s_t_s
  28916. X          Obtain a list of mailing list addresses that  are  ser-
  28917. X          viced by this system, with a small description of their
  28918. X          purpose. If remote lists (see below) are also  defined,
  28919. X          their  addresses  and descriptive messages will also be
  28920. X          included.
  28921. X
  28922. X     _i_n_d_e_x [archive | path-to-archive] [/password] [-all]
  28923. X          Obtain an index of files in the specified  _a_r_c_h_i_v_e  (or
  28924. X          the  master  archive  if none specified) and all of its
  28925. X
  28926. X
  28927. X
  28928. XAnastasios Kotsikonas                                               3
  28929. X
  28930. X
  28931. X
  28932. X
  28933. X
  28934. X
  28935. Xlistproc(1)              USER COMMANDS                listproc(1)
  28936. X
  28937. X
  28938. X
  28939. X          subarchives if the the -_a_l_l option is  specified.  Cer-
  28940. X          tain  archives  may  be  private,  and  these require a
  28941. X          /_p_a_s_s_w_o_r_d to be able to obtain their indices.  Archives
  28942. X          on  different places in the hierarchy may have the same
  28943. X          names and they can be distinguished by specifying paths
  28944. X          to     them;     _p_a_t_h-_t_o-_a_r_c_h_i_v_e     has    the    form
  28945. X          _a_r_c_h_i_v_e[/_a_r_c_h_i_v_e[/_a_r_c_h_i_v_e...]].  _i_n_d_e_x requests  always
  28946. X          report the paths to the archives they list.
  28947. X
  28948. X     _g_e_t <archive | path-to-archive> file [/password] [parts]
  28949. X          Get the specified _f_i_l_e from the _a_r_c_h_i_v_e given. The file
  28950. X          may have been split into smaller parts due to its size,
  28951. X          in which case each part will be  sent  in  a  different
  28952. X          email  message. If only certain _p_a_r_t_s are desired, they
  28953. X          may be given as arguments (numbers, separated by spaces
  28954. X          --  ranges are not recognized). Certain archives may be
  28955. X          private, in which case their /_p_a_s_s_w_o_r_d has to  be  pro-
  28956. X          vided  in  order to get the desired files.  Archives on
  28957. X          different places in the hierarchy  may  have  the  same
  28958. X          names and they can be distinguished by specifying paths
  28959. X          to    them;    _p_a_t_h-_t_o-_a_r_c_h_i_v_e     has     the     form
  28960. X          _a_r_c_h_i_v_e[/_a_r_c_h_i_v_e[/_a_r_c_h_i_v_e...]].   If  the  file is pure
  28961. X          binary, it will be uuencoded first.
  28962. X
  28963. X     _s_e_a_r_c_h <archive | path-to-archive> [/password] [-all]  <pat-
  28964. X          tern>
  28965. X          Search all files in the specified archive (and  all  of
  28966. X          its  subarchives  if  -_a_l_l) and return lines that match
  28967. X          the _p_a_t_t_e_r_n.  The pattern can be  an  extended  regular
  28968. X          expression with egrep(1)-style syntax, with support for
  28969. X          the following additional operators: '~', if leading the
  28970. X          regular expression it reverses its meaning; '|' and '&'
  28971. X          separate multiple regular expressions (logical  OR  and
  28972. X          AND);  '<'  '>'  group regular expressions (we preserve
  28973. X          the meaning of the parentheses from ed(1),  and  remove
  28974. X          the meaning of < and > from ed(1) since in the ListPro-
  28975. X          cessor context they are either the  default,  or  inap-
  28976. X          propriate).   These  can  be used literally by escaping
  28977. X          them with '\'. In addition,  the  following  characters
  28978. X          should be defined in matched pairs: (), <>, []. _p_a_t_t_e_r_n
  28979. X          may be enclosed in single  or  double  quotes.  Pattern
  28980. X          matching is case insensitive.
  28981. X
  28982. X     _f_a_x <fax-no> <archive |  path-to-archive>  file  [/password]
  28983. X          [parts]
  28984. X          Same as the _g_e_t request except that the files are faxed
  28985. X          to the specified number.
  28986. X
  28987. X     _r_e_l_e_a_s_e
  28988. X          Get information  about  the  current  release  of  this
  28989. X          server system.
  28990. X
  28991. X
  28992. X
  28993. X
  28994. XAnastasios Kotsikonas                                               4
  28995. X
  28996. X
  28997. X
  28998. X
  28999. X
  29000. X
  29001. Xlistproc(1)              USER COMMANDS                listproc(1)
  29002. X
  29003. X
  29004. X
  29005. X     _e_x_e_c_u_t_e password #command [arguments]
  29006. X          Intended for the system's _m_a_n_a_g_e_r,  this  will  execute
  29007. X          the   _c_o_m_m_a_n_d  with the optional _a_r_g_u_m_e_n_t_s and send the
  29008. X          output (if  any)  from  stdout  and/or  stderr  to  the
  29009. X          sender. See the sample _c_o_n_f_i_g file for _p_a_s_s_w_o_r_d defini-
  29010. X          tion.
  29011. X
  29012. X     For a list of the list administration requests that  may  be
  29013. X     issued by list owners, see the LIST OWNERS section below.
  29014. X
  29015. XOOOOPPPPTTTTIIIIOOOONNNNSSSS
  29016. X     The following command line options are recognized:
  29017. X
  29018. X     -1   Execute only once; process any requests and return con-
  29019. X          trol  to  _s_e_r_v_e_r_d(1);  any  new  messages that may have
  29020. X          arrived in the meantime will be processed  at  a  later
  29021. X          time.  Without  this option, _l_i_s_t_p_r_o_c will be listening
  29022. X          for requests for ever. _s_e_r_v_e_r_d(1) uses this  option  by
  29023. X          default when spawning _l_i_s_t_e_r_v.
  29024. X
  29025. X     -e   Echo reports to the screen; it has  no  effect  if  the
  29026. X          system has been compiled with -DSYSLOG.
  29027. X
  29028. X     -i   Go to interactive mode -- messages by _l_i_s_t_p_r_o_c are  not
  29029. X          mailed out but instead _s_e_r_v_e_r_d(1) reads them during its
  29030. X          interactive session. Do not use this option in the _c_o_n_-
  29031. X          _f_i_g file (see _s_e_r_v_e_r(_1)).
  29032. X
  29033. X     -n   By default, peer servers are notified  upon  _s_t_a_t_i_s_t_i_c_s
  29034. X          and _r_e_c_i_p_i_e_n_t_s requests. The system uses a protocol for
  29035. X          avoiding loops  as  described  in  _s_e_r_v_e_r(1).   If  you
  29036. X          detect  loops  with  other servers, you should use this
  29037. X          option to turn off notification of peer servers.
  29038. X
  29039. X     -a LIST_ALIAS
  29040. X          Usually, subscriptions are automatic. This option turns
  29041. X          off   automatic  subscription  to  the  specified  list
  29042. X          (_L_I_S_T__A_L_I_A_S should be in capital  letters),  and  makes
  29043. X          this  list  private  (members only may issue _r_e_c_i_p_i_e_n_t_s
  29044. X          and _s_t_a_t_i_s_t_i_c_s requests). The  sender  is  notified  of
  29045. X          this  effect, and a message is sent to the list's owner
  29046. X          requesting  his/her  approval,  with  instructions  for
  29047. X          placing  the  subscription.  Notice  that the specified
  29048. X          list has to be defined beforehand via a _l_i_s_t  directive
  29049. X          in  the  _c_o_n_f_i_g  file.  This option may be repeated any
  29050. X          number of times.
  29051. X
  29052. X     -c LIST_ALIAS
  29053. X          Conceal _L_I_S_T__A_L_I_A_S from _l_i_s_t_s requests.
  29054. X
  29055. X     -r request
  29056. X          Place a restriction on the specified server _r_e_q_u_e_s_t  as
  29057. X
  29058. X
  29059. X
  29060. XAnastasios Kotsikonas                                               5
  29061. X
  29062. X
  29063. X
  29064. X
  29065. X
  29066. X
  29067. Xlistproc(1)              USER COMMANDS                listproc(1)
  29068. X
  29069. X
  29070. X
  29071. X          outlined  above.   If the number of users on the system
  29072. X          at the time the request is about  to  be  processed  is
  29073. X          above  the  limit  given  in the _c_o_n_f_i_g file (using the
  29074. X          _r_e_s_t_r_i_c_t_i_o_n directive),  the  request  is  rejected  --
  29075. X          meant  for requests that may take a considerable amount
  29076. X          of resources such as the  _s_t_a_t_i_s_t_i_c_s  request  --  this
  29077. X          option  may  be  repeated  any  number  of  times. List
  29078. X          administration requests are not subject to  these  res-
  29079. X          trictions (see later on).
  29080. X
  29081. X     -d request
  29082. X          Disable _r_e_q_u_e_s_t, i.e. make it totally  unknown  to  the
  29083. X          server  --  this  supersedes any _d_i_s_a_b_l_e directives for
  29084. X          this request in the _c_o_n_f_i_g file, i.e. this request will
  29085. X          not  be  recognized for any list (see _s_e_r_v_e_r(1)).  How-
  29086. X          ever, help is still available for  that  request.  List
  29087. X          administration  requests are also subject to these res-
  29088. X          trictions (see later on). This option may  be  repeated
  29089. X          any number of times.
  29090. X
  29091. X     -b request
  29092. X          All such  _r_e_q_u_e_s_ts  will  be  batch-processed  if  they
  29093. X          arrive  between the hours specified in the _c_o_n_f_i_g file.
  29094. X          This option may be repeated any number of times.
  29095. X
  29096. X     -B   Process the batch queue. This is done automatically  by
  29097. X          _s_e_r_v_e_r_d(1) after midnight every day, or when the system
  29098. X          is restarted, so no further action needs to  be  taken.
  29099. X          Caution:  do not place this option in the definition of
  29100. X          _s_e_r_v_e_r in the _c_o_n_f_i_g file. If you do so, only the batch
  29101. X          queue  will  be processed (no new requests will be pro-
  29102. X          cessed, ever).  The batch queue is processed once a day
  29103. X          only, unless the system is restarted repeatedly.
  29104. X
  29105. X     -D   Turns debugging on. When the _s_y_s_t_e_m mailmethod is used,
  29106. X          a copy of the last SMTP transaction can be found in the
  29107. X          files HOMEDIR/sent and HOMEDIR/received.
  29108. X
  29109. XPPPPEEEEEEEERRRR SSSSEEEERRRRVVVVEEEERRRRSSSS
  29110. X     The system supports the notion of remote lists.  A  ListPro-
  29111. X     cessor  may  know  of remote lists served by remote servers.
  29112. X     Yet users may send requests about these remote lists to this
  29113. X     server,  which  will  in  turn  forward  them  to the remote
  29114. X     servers. The user is notified when a list is not  local  and
  29115. X     his/her  request  is about to be forwarded.  A _l_i_s_t_s request
  29116. X     will tell the user which remote  lists  are  known  to  this
  29117. X     server.
  29118. X
  29119. X     Remote lists should be made known to  this  server  only  if
  29120. X     they are served by a server of version 5.31 or higher.  This
  29121. X     restriction is posed because of incompatible requests across
  29122. X     various  list  management  systems. See the discussion about
  29123. X
  29124. X
  29125. X
  29126. XAnastasios Kotsikonas                                               6
  29127. X
  29128. X
  29129. X
  29130. X
  29131. X
  29132. X
  29133. Xlistproc(1)              USER COMMANDS                listproc(1)
  29134. X
  29135. X
  29136. X
  29137. X     the _c_o_n_f_i_g file for setting up remote lists.
  29138. X
  29139. X     In addition, _r_e_c_i_p_i_e_n_t_s and  _s_t_a_t_i_s_t_i_c_s  requests  are  for-
  29140. X     warded  to  the  servers handling peer lists (the -n flag to
  29141. X     _l_i_s_t_p_r_o_c turns this feature off).
  29142. X
  29143. XLLLLIIIISSSSTTTT OOOOWWWWNNNNEEEERRRRSSSS
  29144. X     List owners are individuals responsible for list administra-
  29145. X     tion  via  mail  requests. Thus, list owners may be remotely
  29146. X     located. Each list has to have  at  least  one  list  owner.
  29147. X     These owners may be different than the system's _m_a_n_a_g_e_r, and
  29148. X     have special privileges: they may issue requests  on  users'
  29149. X     behalf  (add  a user, remove a user, etc.) overriding system
  29150. X     restrictions set on regular users  (these  include  disabled
  29151. X     commands as described above), obtain reports about the lists
  29152. X     they administer, append to  the  ".aliases"  and  ".ignored"
  29153. X     files,  change  the  welcoming  (".welcome") and informative
  29154. X     (".info") messages, as well as other system  files  such  as
  29155. X     the aliases file (".aliases"), the ".ignored" file, the sub-
  29156. X     scribers file (".subscribers"), the news file (".news")  and
  29157. X     the  peers  file  (".peers"). In addition, they may moderate
  29158. X     their lists and they receive various error messages pertain-
  29159. X     ing  to their lists.  All administrative requests are author
  29160. X     authenticated and password  protected.  Whenever  a  message
  29161. X     cannot be author authenticated, the list's owner and _m_a_n_a_g_e_r
  29162. X     are notified.
  29163. X
  29164. X     On the other hand, list owners may not add restricted users;
  29165. X     this  service  can  be  provided  by contacting the system's
  29166. X     _m_a_n_a_g_e_r.
  29167. X
  29168. X     List owners may also receive copies of user requests  and/or
  29169. X     error  messages  such  as invalid postings, syntax errors on
  29170. X     requests, etc.  These options are described in the following
  29171. X     sections.
  29172. X
  29173. X     Defining list owners
  29174. X          Once a new mailing list is defined in the _c_o_n_f_i_g  file,
  29175. X          the  list's  owner address and access password are pro-
  29176. X          vided to the _l_i_s_t directive.  Of course, this  password
  29177. X          should  be  made  known to the owner; it will be needed
  29178. X          for all  administrative  requests.  Next,  the  owner's
  29179. X          address  has  to  be  registered in HOMEDIR/owners; the
  29180. X          _m_a_n_a_g_e_r simply  edits  this  file  adding  the  owner's
  29181. X          address  along  with  the  list's  name  (alias)  he is
  29182. X          assigned to, followed by any preferences  (see  below).
  29183. X          Multiple  owners  for  a  list may be defined by adding
  29184. X          their addresses to this file, and providing  them  with
  29185. X          the  list's password. However, only the primary owner's
  29186. X          address (as defined by the _l_i_s_t directive) will be used
  29187. X          as  reference  in  correspondence  and for system-error
  29188. X          notifications, and  only  the  primary  owner  will  be
  29189. X
  29190. X
  29191. X
  29192. XAnastasios Kotsikonas                                               7
  29193. X
  29194. X
  29195. X
  29196. X
  29197. X
  29198. X
  29199. Xlistproc(1)              USER COMMANDS                listproc(1)
  29200. X
  29201. X
  29202. X
  29203. X          forwarded  messages  from his moderated list for appro-
  29204. X          val.  The _m_a_n_a_g_e_r should also add  his  address  (login
  29205. X          name) to this file.
  29206. X
  29207. X     Owner preferences
  29208. X          The primary owner may wish  to  be  copied  on  certain
  29209. X          replies  to user requests (such as subscribe), on error
  29210. X          conditions (rejected postings, invalid requests, etc.),
  29211. X          or  on  all  cases. These preferences are listed in the
  29212. X          _o_w_n_e_r_s file on  the  line  his  address  and  list  are
  29213. X          defined. Valid preferences are:
  29214. X
  29215. X            CCSET: copy on _s_e_t requests.
  29216. X
  29217. X            CCSUBSCRIBE: copy on _s_u_b_s_c_r_i_b_e requests.
  29218. X
  29219. X            CCUNSUBSCRIBE: copy on _u_n_s_u_b_s_c_r_i_b_e requests.
  29220. X
  29221. X            CCRECIPIENTS: copy on _r_e_c_i_p_i_e_n_t_s requests.
  29222. X
  29223. X            CCINFORMATION: copy on _i_n_f_o_r_m_a_t_i_o_n requests.
  29224. X
  29225. X            CCSTATISTICS: copy on _s_t_a_t_i_s_t_i_c_s requests.
  29226. X
  29227. X            CCRUN: copy on _r_u_n requests.
  29228. X
  29229. X            CCPRIVATE: copy on requests rejected because they are
  29230. X            open only to the list's members.
  29231. X
  29232. X            CCERRORS: copy on various error conditions.
  29233. X
  29234. X            CCALL: all of the above.
  29235. X
  29236. X          Owner preferences are optional.
  29237. X
  29238. X     The _m_a_n_a_g_e_r may define preferences for himself  as  well  by
  29239. X     using  the keyword _s_e_r_v_e_r in place of a list alias. However,
  29240. X     such preferences make sense only in the following cases:
  29241. X
  29242. X       CCGET: copy on _g_e_t requests.
  29243. X
  29244. X       CCINDEX: copy on _i_n_d_e_x requests.
  29245. X
  29246. X       CCLISTS: copy on _l_i_s_t_s requests.
  29247. X
  29248. X       CCRELEASE: copy on _r_e_l_e_a_s_e requests.
  29249. X
  29250. X       CCHELP: copy on _h_e_l_p requests.
  29251. X
  29252. X       CCERRORS: copy on various error conditions.
  29253. X
  29254. X       CCALL: all of the above.
  29255. X
  29256. X
  29257. X
  29258. XAnastasios Kotsikonas                                               8
  29259. X
  29260. X
  29261. X
  29262. X
  29263. X
  29264. X
  29265. Xlistproc(1)              USER COMMANDS                listproc(1)
  29266. X
  29267. X
  29268. X
  29269. X     Manager preferences are optional.
  29270. X
  29271. X     Owner privileges
  29272. X          Whenever an owner issues a user  request  on  a  user's
  29273. X          behalf  (see  below),  all restrictions, including dis-
  29274. X          abled commands, do not apply. All other  administrative
  29275. X          requests   are  subject  to  restrictions  set  by  the
  29276. X          _m_a_n_a_g_e_r.  All requests (user  and  administrative)  are
  29277. X          subject to batch-processing.
  29278. X
  29279. X     Administrative requests
  29280. X          The following requests may be issued by a list's owner:
  29281. X
  29282. X     _s_y_s_t_e_m list password user-address #user-request
  29283. X          This request overrides all system restrictions and exe-
  29284. X          cutes  _u_s_e_r-_r_e_q_u_e_s_t  on  behalf  of  _u_s_e_r-_a_d_d_r_e_s_s; this
  29285. X          address has to appear as listed in  the  ".subscribers"
  29286. X          file,  where  applicable.  The most frequent use of the
  29287. X          _s_y_s_t_e_m request is to subscribe  a  user  to  a  private
  29288. X          list. For example:
  29289. X
  29290. X            system herc herc1 john@foo #subscribe herc Some Name
  29291. X
  29292. X          If a _u_s_e_r-_r_e_q_u_e_s_t refers to a list, this list has to be
  29293. X          _l_i_s_t,  so  that  a list's owner may not have privileges
  29294. X          over another list's  affairs.  Note  that  all  replies
  29295. X          about  _u_s_e_r-_r_e_q_u_e_s_t  are forwarded to _u_s_e_r-_a_d_d_r_e_s_s, not
  29296. X          the owner; therefore, care has to  be  taken  to  avoid
  29297. X          syntax  errors.  The  _s_y_s_t_e_m  request is not subject to
  29298. X          restrictions, disabled requests, and private list  sub-
  29299. X          scription  verification (it is still subject to private
  29300. X          list review as outlined above, and batching). To remove
  29301. X          a member from his list, the owner may issue the follow-
  29302. X          ing request:
  29303. X
  29304. X            system herc herc1 john@foo #unsubscribe herc
  29305. X
  29306. X          To bypass restrictions and review his list,  the  owner
  29307. X          may issue the following:
  29308. X
  29309. X            system venus venus1 his-address #review venus
  29310. X
  29311. X          In general, _u_s_e_r-_r_e_q_u_e_s_t may be any of  the  recognized
  29312. X          user  requests described under _l_i_s_t_p_r_o_c. The pound sign
  29313. X          is mandatory.  There is no help available to users  for
  29314. X          this request for security reasons.
  29315. X
  29316. X     _a_p_p_r_o_v_e list password tag
  29317. X          Whenever a new message arrives for a moderated  list  a
  29318. X          copy  is sent to the list's owner soliciting his appro-
  29319. X          val -- proper instructions for approving or  discarding
  29320. X          a  message  are  included.  This  request  approves the
  29321. X
  29322. X
  29323. X
  29324. XAnastasios Kotsikonas                                               9
  29325. X
  29326. X
  29327. X
  29328. X
  29329. X
  29330. X
  29331. Xlistproc(1)              USER COMMANDS                listproc(1)
  29332. X
  29333. X
  29334. X
  29335. X          message identified by the _t_a_g  number  for  posting  to
  29336. X          _l_i_s_t. The tag number is provided to the list's owner by
  29337. X          _l_i_s_t_p_r_o_c and is unique.
  29338. X
  29339. X     _d_i_s_c_a_r_d list password tag
  29340. X          In contrast to the above  request,  this  discards  the
  29341. X          message  identified  by  _t_a_g.  Messages  that  are  not
  29342. X          approved or discarded remain in  the  list's  _m_o_d_e_r_a_t_e_d
  29343. X          file (see _l_i_s_t(1)).
  29344. X
  29345. X     _r_e_p_o_r_t_s list password
  29346. X          Obtain all reports pertinent to _l_i_s_t;  this  will  send
  29347. X          two   mail  messages:   one  with  the  current  report
  29348. X          (HOMEDIR/lists/ALIAS/.report.list), and  one  with  the
  29349. X          previously                 archived                ones
  29350. X          (HOMEDIR/lists/ALIAS/.rep.list.acc);  see  the  REPORTS
  29351. X          section  below.  Once the ".rep.list.acc" file is sent,
  29352. X          it is shrunk in size, therefore the owner  should  make
  29353. X          sure he keeps the copy he receives.
  29354. X
  29355. X          This request has no effect if the system is using  sys-
  29356. X          log(3) to generate reports.
  29357. X
  29358. X     _e_d_i_t list password file
  29359. X          Obtain the specified _f_i_l_e for editing; candidate  files
  29360. X          are:
  29361. X
  29362. X            _a_l_i_a_s_e_s: obtain the list's aliases file.
  29363. X
  29364. X            _i_g_n_o_r_e_d:  obtain  the  list's   list   of   unwelcome
  29365. X            addresses.
  29366. X
  29367. X            _i_n_f_o: obtain the list's informative message.
  29368. X
  29369. X            _s_u_b_s_c_r_i_b_e_r_s: obtain the list's subscribers list.
  29370. X
  29371. X            _w_e_l_c_o_m_e: obtain the list's welcoming message.
  29372. X
  29373. X            _n_e_w_s: obtain the list's  list  of  newsgroup  connec-
  29374. X            tions.
  29375. X
  29376. X            _p_e_e_r_s: obtain the list's peers.
  29377. X
  29378. X     _p_u_t list password keyword [args]
  29379. X          This  enables  the  list's  owner  to  append  to   the
  29380. X          ".aliases" and ".ignored" files, and replace his list's
  29381. X          ".welcome",  ".info",  ".aliases",  ".ignored",  ".sub-
  29382. X          scribers", ".news" and ".peers" files, depending on the
  29383. X          _k_e_y_w_o_r_d. Valid _k_e_y_w_o_r_ds are:
  29384. X
  29385. X            _a_l_i_a_s: Add a user address alias  to  the  list's  and
  29386. X            system's  ".aliases" files (see .ALIASES below). This
  29387. X
  29388. X
  29389. X
  29390. XAnastasios Kotsikonas                                              10
  29391. X
  29392. X
  29393. X
  29394. X
  29395. X
  29396. X
  29397. Xlistproc(1)              USER COMMANDS                listproc(1)
  29398. X
  29399. X
  29400. X
  29401. X            requires the new address and  the  address  used  for
  29402. X            subscription as arguments:
  29403. X
  29404. X            put <list> <password> alias <new-alias>  <address-as-
  29405. X            subscribed>
  29406. X
  29407. X            For example:
  29408. X
  29409. X              put venus venus1 alias foo!john john@foo
  29410. X
  29411. X            _i_g_n_o_r_e: Add a user address to  the  list's  ".ignore"
  29412. X            file  only. Of course this address has to be provided
  29413. X            as argument:
  29414. X
  29415. X            put <list> <password> ignore  <address-as-subscribed-
  29416. X            or-aliased>
  29417. X
  29418. X            For example:
  29419. X
  29420. X              put ermis ermis1 ignore jack@foo
  29421. X              put ermis ermis1 ignore foo!jack
  29422. X
  29423. X            _w_e_l_c_o_m_e,
  29424. X            _i_n_f_o,
  29425. X            _a_l_i_a_s_e_s,
  29426. X            _i_g_n_o_r_e_d,
  29427. X            _s_u_b_s_c_r_i_b_e_r_s,
  29428. X            _n_e_w_s,
  29429. X            _p_e_e_r_s: Create a new system file.
  29430. X
  29431. X            For example:
  29432. X
  29433. X              put <list> <password> subscribers
  29434. X              tasos ACK PASSWORD NO Tasos Kotsikonas
  29435. X              john NOACK PASS1 NO John Doe
  29436. X
  29437. X            No arguments are needed. The text that is  to  go  to
  29438. X            the  corresponding  file starts at the line following
  29439. X            this request and spans till the end of the mail  mes-
  29440. X            sage.  Thus, no more requests can be made in the same
  29441. X            mail message -- they are  treated  as  regular  text;
  29442. X            signature  lines  also  signify the end of text, pro-
  29443. X            vided they start with "--" in a single line.
  29444. X
  29445. X          A confirmation is sent to the owner once a _p_u_t  request
  29446. X          is successfully processed.
  29447. X
  29448. XOOOOWWWWNNNNEEEERRRRSSSS
  29449. X     The format of the _o_w_n_e_r_s file is as follows:
  29450. X
  29451. X     One entry per line; each entry is the full email address  of
  29452. X     a list's owner, followed by the list alias he owns, followed
  29453. X
  29454. X
  29455. X
  29456. XAnastasios Kotsikonas                                              11
  29457. X
  29458. X
  29459. X
  29460. X
  29461. X
  29462. X
  29463. Xlistproc(1)              USER COMMANDS                listproc(1)
  29464. X
  29465. X
  29466. X
  29467. X     by any optional preferences. If the keyword _s_e_r_v_e_r is speci-
  29468. X     fied  in  place  of  the  list  alias,  then preferences are
  29469. X     defined for the _m_a_n_a_g_e_r.
  29470. X
  29471. XSSSSEEEEEEEE AAAALLLLSSSSOOOO
  29472. X     catmail(1), farch(1),  list(1),  queue(1),  server(1),  ser-
  29473. X     verd(1), start(1)
  29474. X
  29475. XAAAAUUUUTTTTHHHHOOOORRRR
  29476. X     Anastasios C. Kotsikonas
  29477. X     Copyright (c) 1991-93, Anastasios Kotsikonas
  29478. X     Comments to tasos@cs.bu.edu
  29479. X
  29480. X
  29481. X
  29482. X
  29483. X
  29484. X
  29485. X
  29486. X
  29487. X
  29488. X
  29489. X
  29490. X
  29491. X
  29492. X
  29493. X
  29494. X
  29495. X
  29496. X
  29497. X
  29498. X
  29499. X
  29500. X
  29501. X
  29502. X
  29503. X
  29504. X
  29505. X
  29506. X
  29507. X
  29508. X
  29509. X
  29510. X
  29511. X
  29512. X
  29513. X
  29514. X
  29515. X
  29516. X
  29517. X
  29518. X
  29519. X
  29520. X
  29521. X
  29522. XAnastasios Kotsikonas                                              12
  29523. X
  29524. X
  29525. X
  29526. *-*-END-of-doc/listproc.nr-*-*
  29527. echo x - doc/queue.nr
  29528. sed 's/^X//' >doc/queue.nr <<'*-*-END-of-doc/queue.nr-*-*'
  29529. X
  29530. X
  29531. X
  29532. Xqueue(1)                 USER COMMANDS                   queue(1)
  29533. X
  29534. X
  29535. X
  29536. XNNNNAAAAMMMMEEEE
  29537. X     qqqquuuueeeeuuuueeeedddd - ListProcessor mail queue daemon
  29538. X
  29539. XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
  29540. X     qqqquuuueeeeuuuueeeedddd <ffffrrrreeeeqqqquuuueeeennnnccccyyyy>
  29541. X
  29542. XNNNNAAAAMMMMEEEE
  29543. X     ppppqqqquuuueeeeuuuueeee - process the specified mail queue files
  29544. X
  29545. XSSSSYYYYNNNNOOOOPPPPSSSSIIIISSSS
  29546. X     ppppqqqquuuueeeeuuuueeee [----eeee] [----DDDD] <ffffiiiilllleeeessss>
  29547. X
  29548. XOOOOVVVVEEEERRRRVVVVIIIIEEEEWWWW
  29549. X     This part of the ListProcessor system can be  employed  only
  29550. X     when  using the _s_y_s_t_e_m mailmethod (see _s_e_r_v_e_r(1)).  Messages
  29551. X     and replies to requests not delivered due to  network  prob-
  29552. X     lems   are   queued   by   the   system   in  the  directory
  29553. X     HOMEDIR/mqueue. This part of the  system  attempts  periodic
  29554. X     redelivery  of these files. If problems still persist, files
  29555. X     (messages) that cannot be delivered are requeued.
  29556. X
  29557. XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN:::: qqqquuuueeeeuuuueeeedddd
  29558. X     This is the daemon that looks for files in the  mail  queue.
  29559. X     It  uses  _p_q_u_e_u_e  for redelivery. The queue is checked every
  29560. X     _f_r_e_q_u_e_n_c_y seconds. Whenever an  error  occurs  with  _p_q_u_e_u_e,
  29561. X     _q_u_e_u_e_d  sends  a  mail message to _m_a_n_a_g_e_r (as defined in the
  29562. X     _c_o_n_f_i_g file) and aborts.
  29563. X
  29564. X     _q_u_e_u_e_d is not spawned by _s_t_a_r_t(1) in  order  to  reduce  the
  29565. X     number  of  processes running, since the probability of mes-
  29566. X     sages being queued  is  very  low.  Instead,  it  should  be
  29567. X     started  manually whenever there are files in the mail queue
  29568. X     directory.
  29569. X
  29570. XDDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN:::: ppppqqqquuuueeeeuuuueeee
  29571. X     The _f_i_l_e_s given as arguments  are  redelivered.  If  any  of
  29572. X     these  cannot  be redelivered, they are requeued and will be
  29573. X     processed in the  next  run.  _p_q_u_e_u_e  reports  to  the  file
  29574. X     HOMEDIR/.report.pqueue
  29575. X
  29576. X     The following command line options are recognized:
  29577. X
  29578. X     -e   Echo reports to the screen; it has  no  effect  if  the
  29579. X          system has been compiled with -DSYSLOG.
  29580. X
  29581. X     -D   Turns debugging on; a copy of the last SMTP transaction
  29582. X          can   be   found   in   the   files   HOMEDIR/sent  and
  29583. X          HOMEDIR/received. Warning: these files are also used by
  29584. X          _l_i_s_t(1) and _l_i_s_t_p_r_o_c(1) when they have their debug mode
  29585. X          on, so use caution.
  29586. X
  29587. X
  29588. X
  29589. X
  29590. X
  29591. XAnastasios Kotsikonas                                               1
  29592. X
  29593. X
  29594. X
  29595. X
  29596. X
  29597. X
  29598. Xqueue(1)                 USER COMMANDS                   queue(1)
  29599. X
  29600. X
  29601. X
  29602. XNNNNOOOOTTTTEEEE
  29603. X     This mail queueing system should not be  confused  with  the
  29604. X     one implemented by sendmail(1).
  29605. X
  29606. XSSSSEEEEEEEE AAAALLLLSSSSOOOO
  29607. X     server(1)
  29608. X
  29609. XAAAAUUUUTTTTHHHHOOOORRRR
  29610. X     Anastasios C. Kotsikonas
  29611. X     Copyright (c) 1991-93, Anastasios Kotsikonas
  29612. X     Comments to tasos@cs.bu.edu
  29613. X
  29614. X
  29615. X
  29616. X
  29617. X
  29618. X
  29619. X
  29620. X
  29621. X
  29622. X
  29623. X
  29624. X
  29625. X
  29626. X
  29627. X
  29628. X
  29629. X
  29630. X
  29631. X
  29632. X
  29633. X
  29634. X
  29635. X
  29636. X
  29637. X
  29638. X
  29639. X
  29640. X
  29641. X
  29642. X
  29643. X
  29644. X
  29645. X
  29646. X
  29647. X
  29648. X
  29649. X
  29650. X
  29651. X
  29652. X
  29653. X
  29654. X
  29655. X
  29656. X
  29657. XAnastasios Kotsikonas                                               2
  29658. X
  29659. X
  29660. X
  29661. *-*-END-of-doc/queue.nr-*-*
  29662. echo x - doc/server.nr
  29663. sed 's/^X//' >doc/server.nr <<'*-*-END-of-doc/server.nr-*-*'
  29664. X
  29665. X
  29666. X
  29667. Xserver(1)                USER COMMANDS                  server(1)
  29668. X
  29669. X
  29670. X
  29671. XNNNNAAAAMMMMEEEE
  29672. X     ListProcessor version 6.0
  29673. X
  29674. XOOOOVVVVEEEERRRRVVVVIIIIEEEEWWWW
  29675. X     This is a system that implements various mailing lists  with
  29676. X     one  list manager. It is automated, and obliterates the need
  29677. X     for user intervention and maintenance of multiple aliases of
  29678. X     the  form  "list,  list-owner,  list-request", etc. There is
  29679. X     support  provided  for  public  and   private   hierarchical
  29680. X     archives,  moderated  and  non-moderated  lists, peer lists,
  29681. X     peer servers, private lists, address aliasing, news  connec-
  29682. X     tions  and gateways, mail queueing, digests, list ownership,
  29683. X     owner preferences, crash recovery, batch processing,  confi-
  29684. X     gurable headers, regular expressions, archive searching, and
  29685. X     live user connections via TCP/IP.
  29686. X
  29687. XOOOOBBBBTTTTAAAAIIIINNNNIIIINNNNGGGG IIIINNNNFFFFOOOORRRRMMMMAAAATTTTIIIIOOOONNNN
  29688. X     mailing lists, aliases, news groups, peer lists
  29689. X          See list(1).
  29690. X
  29691. X     user requests, list owners, peer servers, remote lists
  29692. X          See listproc(1).
  29693. X
  29694. X     distributing incoming mail
  29695. X          See catmail(1).
  29696. X
  29697. X     archiving files
  29698. X          See farch(1).
  29699. X
  29700. X     archiving of lists' messages
  29701. X          See below.
  29702. X
  29703. X     processing the mail queue
  29704. X          See queue(1).
  29705. X
  29706. X     options for the system's daemon
  29707. X          See serverd(1).
  29708. X
  29709. X     starting and stopping the system
  29710. X          See start(1).
  29711. X
  29712. X     live connections
  29713. X          See ilp(1) and serverd(1).
  29714. X
  29715. XSSSSYYYYSSSSTTTTEEEEMMMM SSSSEEEETTTTUUUUPPPP
  29716. X     The ListProcessor system  is  installed  under  the  HOMEDIR
  29717. X     directory  as defined in src/Makefile; HOMEDIR points to the
  29718. X     top level directory  of  the  installation;  a  _s_e_r_v_e_r  user
  29719. X     account  has to be setup. The system should be installed and
  29720. X     set up using this account, and always be started  from  this
  29721. X     account  as  well (see _s_t_a_r_t(1)).  Then, the following alias
  29722. X     has to  be  defined  in  /etc/aliases,  /usr/lib/aliases  or
  29723. X
  29724. X
  29725. X
  29726. XKubota Computer                                                 1
  29727. X
  29728. X
  29729. X
  29730. X
  29731. X
  29732. X
  29733. Xserver(1)                USER COMMANDS                  server(1)
  29734. X
  29735. X
  29736. X
  29737. X     /usr/ucblib/aliases  (depending on your system) for listpro-
  29738. X     cessor (where users send their requests):
  29739. X
  29740. X       listproc: "|HOMEDIR/catmail -r -f"
  29741. X
  29742. X     Various mailing lists are set up in a similar  fashion;  see
  29743. X     _l_i_s_t(1).
  29744. X
  29745. X     It is important to keep in mind that mailers should  convert
  29746. X     any  text  lines  (not  header  lines)  of incoming messages
  29747. X     starting with "From ", to ">From ".  This  is  automatically
  29748. X     done by the -f flag to _c_a_t_m_a_i_l(1).
  29749. X
  29750. X     The _c_a_t_m_a_i_l(1) utility is used to append  incoming  mail  to
  29751. X     the  appropriate  files.  When  properly  set up, it has the
  29752. X     setuid bit turned on. Since execute permission is granted to
  29753. X     everybody,  it  is  possible  for  anyone to append to these
  29754. X     files; however, each time _c_a_t_m_a_i_l(1) is run, it reports  the
  29755. X     user id and user name whom access was granted to.
  29756. X
  29757. X     If the system is to go  interactive  (see  _s_e_r_v_e_r_d(1)),  you
  29758. X     have to add the following line in your /etc/services file:
  29759. X
  29760. X                         ulistproc   372/tcp
  29761. X
  29762. X     See also src/Makefile.
  29763. X
  29764. X     How the system operates is defined in the _c_o_n_f_i_g  file  (see
  29765. X     below).  Once the system is loaded, you will have to run the
  29766. X     script _s_e_t_u_p; this will ensure that all necessary files  and
  29767. X     directories  are  present,  and  have the right permissions.
  29768. X     Before starting  the  system,  you  may  wish  to  edit  the
  29769. X     ".ignored"  file  in  HOMEDIR (see _l_i_s_t(1)).  At this point,
  29770. X     you may also wish to alter the help files  in  HOMEDIR/help;
  29771. X     each file in that directory corresponds to one of the recog-
  29772. X     nized requests.  Help files may be  simple  text  files,  or
  29773. X     shell  scripts  starting  with "#!"  in the first line, fol-
  29774. X     lowed by the shell to execute.
  29775. X
  29776. X     File protections are a major issue and the requirements  may
  29777. X     vary  from system to system. The problems usually arise from
  29778. X     inadequate write permissions while  appending  mail  to  the
  29779. X     various mail files. The system uses the environment variable
  29780. X     ULISTPROC_UMASK in the same way as  umask(1)  is  used  when
  29781. X     updating  files.  If not set, the default is 066. A value of
  29782. X     026 should be acceptable in most cases. This variable should
  29783. X     be  set in both .cshrc and .profile. For archived files, you
  29784. X     may  use  the   ULISTPROC_ARCHIVES_UMASK   variable,   which
  29785. X     defaults to the value set for ULISTPROC_UMASK.
  29786. X
  29787. X     Finally, experiment with the various mail methods  described
  29788. X     below,  until  you  get  the  proper  "From  "  line  in the
  29789. X
  29790. X
  29791. X
  29792. XKubota Computer                                                 2
  29793. X
  29794. X
  29795. X
  29796. X
  29797. X
  29798. X
  29799. Xserver(1)                USER COMMANDS                  server(1)
  29800. X
  29801. X
  29802. X
  29803. X     beginning of the outgoing message; for instance, when  _l_i_s_t_-
  29804. X     _p_r_o_c(1)  is  replying to a request, you should see something
  29805. X     like "From listproc@your-domain" as the first  line  of  the
  29806. X     header;  or when the list abc is distributing messages, this
  29807. X     line should look like "From abc@your-domain". If you  cannot
  29808. X     get   it   to  work,  i.e.  you  get  something  like  "From
  29809. X     server@your-domain" then the server system may have  to  run
  29810. X     with  superuser  privileges. In this case, the server userid
  29811. X     should be the same as root's. Also consult the PORT SPECIFIC
  29812. X     section  below, for suggested mailmethods. You will not have
  29813. X     any of these problems if you use the _s_y_s_t_e_m mailmethod  (see
  29814. X     below).
  29815. X
  29816. X     If this part of the setup is not done properly,  peer  lists
  29817. X     will  not  work at all and users may not be able to reply to
  29818. X     the list. As a final note, if _t_e_l_n_e_t does  not  seem  to  be
  29819. X     sending any mail, it is a bug with the telnet implementation
  29820. X     on your system: telnet cannot have its input  redirected  or
  29821. X     piped, and should be reported to your vendor.
  29822. X
  29823. X     The last step for a complete set up is to define your system
  29824. X     in the _c_o_n_f_i_g file.
  29825. X
  29826. XCCCCOOOONNNNFFFFIIIIGGGG
  29827. X     The server system is defined in the _c_o_n_f_i_g file; an  example
  29828. X     file  is  provided  with  the  system.  This file is used by
  29829. X     _s_t_a_r_t(1), _s_e_r_v_e_r_d(1), _l_i_s_t(1) and _l_i_s_t_p_r_o_c(1), and is not  a
  29830. X     shell script.
  29831. X
  29832. X     The following keywords (directives) are  recognized  and  is
  29833. X     advisable  that  each one of them starts at column 1; direc-
  29834. X     tives may span multiple lines if each line is terminated  by
  29835. X     &\n:
  29836. X
  29837. X     _o_r_g_a_n_i_z_a_t_i_o_n name
  29838. X          This defines your organization when posting to news and
  29839. X          upon  connection  establishment of a live session. _n_a_m_e
  29840. X          may include blanks.
  29841. X
  29842. X     _s_e_r_v_e_r _l_i_s_t_p_r_o_c@your-domain command-line-options
  29843. X          This defines the list processor; the first argument  is
  29844. X          the   full   email   address   of   the   server  (e.g.
  29845. X          listproc@foo.edu) followed by any command line  options
  29846. X          to  be  used  when  _s_e_r_v_e_r_d  spawns  _l_i_s_t_p_r_o_c (see _s_e_r_-
  29847. X          _v_e_r_d(1), _l_i_s_t_p_r_o_c(1)).
  29848. X
  29849. X     _l_i_s_t list_alias email-addr owner-addr password cmd-line-opt
  29850. X          This defines a mailing list; the first argument is  the
  29851. X          list's   alias  in  /etc/aliases,  /usr/lib/aliases  or
  29852. X          /usr/ucblib/aliases (see _l_i_s_t(1)), followed by its full
  29853. X          email  address,  followed  by  its  owner's  full email
  29854. X          address,  followed   by   the   list's   password   for
  29855. X
  29856. X
  29857. X
  29858. XKubota Computer                                                 3
  29859. X
  29860. X
  29861. X
  29862. X
  29863. X
  29864. X
  29865. Xserver(1)                USER COMMANDS                  server(1)
  29866. X
  29867. X
  29868. X
  29869. X          maintenance, followed by any command line options to be
  29870. X          used when _s_e_r_v_e_r_d(1) spawns _l_i_s_t(1).
  29871. X
  29872. X     _h_e_a_d_e_r list { [Header-Line:] ... }
  29873. X          It specifies precious header lines  from  the  original
  29874. X          sender's  message  that are to be preserved during dis-
  29875. X          tribution. The _l_i_s_t has to be defined before, and  pre-
  29876. X          cious header lines are specified within the enclosing {
  29877. X          and }, possibly spanning multiple lines.
  29878. X
  29879. X     _d_e_f_a_u_l_t list { [option = value] ... }
  29880. X          Determine various default values for _l_i_s_t for  new  and
  29881. X          current subscribers; the list has to be defined before.
  29882. X          Pairs of options and values may be repeated any  number
  29883. X          of  times,  and  may  span  multiple  lines; if certain
  29884. X          options are missing, then  system  defaults  are  used.
  29885. X          Valid _o_p_t_i_o_ns are:
  29886. X
  29887. X            _a_d_d_r_e_s_s: turn user-settable subscription addresses on
  29888. X            or off. Valid values are:
  29889. X
  29890. X              _f_i_x_e_d: users are not allowed to change the  address
  29891. X              they are subscribed with via the _s_e_t <_l_i_s_t> _a_d_d_r_e_s_s
  29892. X              request (see  _l_i_s_t_p_r_o_c(1)).   This  is  the  system
  29893. X              default as well.
  29894. X
  29895. X              _v_a_r_i_a_b_l_e: opposite of the above.
  29896. X
  29897. X            _m_a_i_l: select the  default  mail  mode  for  new  sub-
  29898. X            scribers. Valid values are:
  29899. X
  29900. X              _a_c_k: see _s_e_t in _l_i_s_t_p_r_o_c(1).
  29901. X
  29902. X              _n_o_a_c_k: see _s_e_t in _l_i_s_t_p_r_o_c(1); this is  the  system
  29903. X              default.
  29904. X
  29905. X              _p_o_s_t_p_o_n_e: see _s_e_t in _l_i_s_t_p_r_o_c(1) (a rather  useless
  29906. X              setting indeed).
  29907. X
  29908. X              _d_i_g_e_s_t: see _s_e_t in _l_i_s_t_p_r_o_c(1).
  29909. X
  29910. X            _p_a_s_s_w_o_r_d: define a single password for new users;  if
  29911. X            missing,  the  system  assigns a random password. Any
  29912. X            string that contains no white spaces may be used.
  29913. X
  29914. X            _c_o_n_c_e_a_l: determine  the  default  visibility  of  new
  29915. X            users; see _s_e_t in _l_i_s_t_p_r_o_c(1). Valid options are:
  29916. X
  29917. X              _y_e_s:  hidden   from   _r_e_c_i_p_i_e_n_t_s   and   _s_t_a_t_i_s_t_i_c_s
  29918. X              requests.
  29919. X
  29920. X              _n_o: this is the system default.
  29921. X
  29922. X
  29923. X
  29924. XKubota Computer                                                 4
  29925. X
  29926. X
  29927. X
  29928. X
  29929. X
  29930. X
  29931. Xserver(1)                USER COMMANDS                  server(1)
  29932. X
  29933. X
  29934. X
  29935. X     _c_e_i_l_i_n_g list max_messages
  29936. X          Restrict the number of  messages  processed  daily  for
  29937. X          _l_i_s_t to _m_a_x__m_e_s_s_a_g_e_s; this includes posted and rejected
  29938. X          messages.
  29939. X
  29940. X     _r_e_m_o_t_e alias email-addr listproc-addr [host [port]] #Comment
  29941. X          This makes a remote list known to the server. A  remote
  29942. X          list  is another mailing list served by another server,
  29943. X          and your server is now capable  of  forwarding  to  the
  29944. X          proper  remote  list  processor any requests sent about
  29945. X          this remote list to your server. _a_l_i_a_s is the  name  by
  29946. X          which  the  remote  list is known by, _e_m_a_i_l-_a_d_d_r is the
  29947. X          full email address of the remote list, _l_i_s_t_p_r_o_c-_a_d_d_r is
  29948. X          the  full  email  address of the remote list processor,
  29949. X          and #_C_o_m_m_e_n_t will be used upon a _l_i_s_t_s request made  to
  29950. X          this  server  (the  pound  sign  is mandatory). _h_o_s_t is
  29951. X          either the DNS name or IP address of the remote server,
  29952. X          used  to  connect  to  that  server when a live request
  29953. X          refers to that list; the _p_o_r_t should  be  specified  if
  29954. X          not the default (372) (see _s_e_r_v_e_r_d(1)).
  29955. X
  29956. X          Remote lists may have the same _a_l_i_a_s  and  they  should
  29957. X          not  be  confused with peer lists. However, each remote
  29958. X          list should be defined only once.  See  the  discussion
  29959. X          about  PEER SERVERS  (_l_i_s_t_p_r_o_c(1)) for further informa-
  29960. X          tion.
  29961. X
  29962. X     _f_a_x fax-program options
  29963. X          Define the fax program to use for _f_a_x requests (if any)
  29964. X          and  any  command line options the program may use. The
  29965. X          program should also be capable of accepting the file to
  29966. X          fax  from  its  standard input; otherwise a script will
  29967. X          have to be used instead which will in turn use the  fax
  29968. X          program  appropriately.  If  this  directive is left or
  29969. X          commented out,  then  _f_a_x  requests  are  automatically
  29970. X          turned off.
  29971. X
  29972. X          The actual faxing program is called as follows:
  29973. X
  29974. X                   _f_a_x-_p_r_o_g_r_a_m _o_p_t_i_o_n_s fax-number < file
  29975. X
  29976. X          This request may not be issued  from  a  live  session,
  29977. X          since  fax  programs work on email messages and extract
  29978. X          the sender's address for  reference  when  sending  the
  29979. X          cover page of the fax.
  29980. X
  29981. X     _u_n_i_x__c_m_d  list_alias  password  name  'unix-command  [args]'
  29982. X          #Comment
  29983. X          Allow a _l_i_s_t__a_l_i_a_s's subscribers only  to  execute  the
  29984. X          above  _u_n_i_x-_c_o_m_m_a_n_d  aliased  to  _n_a_m_e. The _p_a_s_s_w_o_r_d is
  29985. X          made known to users who are to be given this privilege.
  29986. X          The  oprional  _a_r_g_s  may  be  literal  arguments to the
  29987. X
  29988. X
  29989. X
  29990. XKubota Computer                                                 5
  29991. X
  29992. X
  29993. X
  29994. X
  29995. X
  29996. X
  29997. Xserver(1)                USER COMMANDS                  server(1)
  29998. X
  29999. X
  30000. X
  30001. X          command as well as the special sequences $_n, where _n is
  30002. X          a digit from 1 to 9, or *; their meaning is that of the
  30003. X          Bourne shell, and  they  will  be  substituted  by  the
  30004. X          user's actual arguments. For example:
  30005. X
  30006. X          unix_cmd ermis pass1 swap '/bin/echo $2 $1' #Syntax: swap <arg1> <arg2>
  30007. X
  30008. X          will swap the user's first and  second  arguments.  The
  30009. X          user would submit a request that could look like this:
  30010. X
  30011. X                      run ermis pass1 swap arg1 arg2
  30012. X
  30013. X          No security checks are made except to ensure  that  the
  30014. X          arguments  contain  no `, |, :, < and >, so the _m_a_n_a_g_e_r
  30015. X          is encouraged to review and verify the proper function-
  30016. X          ing  of  _u_n_i_x-_c_o_m_m_a_n_d.  The  _C_o_m_m_e_n_t is used when users
  30017. X          issue 'run <list>' query requests.
  30018. X
  30019. X     _s_e_r_v_e_r_d command-line-options
  30020. X          This defines the command line options that _s_t_a_r_t(1)  is
  30021. X          to use when spawning _s_e_r_v_e_r_d(1).
  30022. X
  30023. X     _r_e_s_t_r_i_c_t_i_o_n nusers
  30024. X          If a restriction is placed on a  ListProcessor  request
  30025. X          (via  a  -r  command  line option to _l_i_s_t_p_r_o_c(1)), this
  30026. X          directive defines the threshold number of users,  above
  30027. X          which the restriction will take effect.
  30028. X
  30029. X     _d_i_s_a_b_l_e list_alias request
  30030. X          The specified server _r_e_q_u_e_s_t is disabled for the speci-
  30031. X          fied  list,  and  all  such  requests for this list are
  30032. X          rejected, except when issued by privileged users  (list
  30033. X          owners).  The  _l_i_s_t__a_l_i_a_s has to be defined (via a _l_i_s_t
  30034. X          directive) before any requests can be disabled.
  30035. X
  30036. X     _m_a_n_a_g_e_r full-email-address
  30037. X          This defines the recipient of  all  system  error  mes-
  30038. X          sages,  and  the  system's administrator and caretaker;
  30039. X          _f_u_l_l-_e_m_a_i_l-_a_d_d_r_e_s_s can be any valid user name that  can
  30040. X          be  reached  via  email by your system.  The _m_a_n_a_g_e_r is
  30041. X          usually the person responsible for the server account.
  30042. X
  30043. X     _c_o_m_m_e_n_t _s_e_r_v_e_r #Actual comment
  30044. X
  30045. X     _c_o_m_m_e_n_t list_alias #Actual comment
  30046. X          A 'X-Comment:'  line  is  included  in  every  outgoing
  30047. X          list/server  message,  and the text following the pound
  30048. X          sign will be copied every time;  note  that  the  pound
  30049. X          sign  is  mandatory  for the definition but will not be
  30050. X          part of the actual string.  A list's  comment  is  also
  30051. X          used  for  the  _l_i_s_t_s request to specify the purpose of
  30052. X          the particular mailing list. No  'X-Comment:'  line  is
  30053. X
  30054. X
  30055. X
  30056. XKubota Computer                                                 6
  30057. X
  30058. X
  30059. X
  30060. X
  30061. X
  30062. X
  30063. Xserver(1)                USER COMMANDS                  server(1)
  30064. X
  30065. X
  30066. X
  30067. X          included  if this directive is not defined for the par-
  30068. X          ticular list and/or server.
  30069. X
  30070. X     _d_i_g_e_s_t list_alias lines hours
  30071. X          If any subscriber to the list requests digests, a  dig-
  30072. X          est will be sent when its length exceeds _l_i_n_e_s, or when
  30073. X          _h_o_u_r_s have passed without a digest being sent.  Digests
  30074. X          for  a  list  are collected only if at least one of its
  30075. X          subscribers has set his mail mode to _d_i_g_e_s_t.
  30076. X
  30077. X     _a_r_c_h_i_v_e list_alias dir filename [archive]  [password]  [dig-
  30078. X          est]
  30079. X          Request that  all  public  messages  are  automatically
  30080. X          archived;  _l_i_s_t__a_l_i_a_s  is  the  list's name, _d_i_r is the
  30081. X          directory that the archived files will  be  located  (a
  30082. X          full path has to be specified, and the directory has to
  30083. X          be  writable  by  the  server  uid),  _a_r_c_h_i_v_e  is   the
  30084. X          archive's name and is a relative path under the default
  30085. X          archive (listproc) or "-" for the default, _p_a_s_s_w_o_r_d  is
  30086. X          an  optional  password  ("-" if none) to be used if the
  30087. X          archive is meant to be private, and the  optional  key-
  30088. X          word  _d_i_g_e_s_t  will  force  only digests to be archived;
  30089. X          _f_i_l_e_n_a_m_e specifies the format of  the  archived  files,
  30090. X          and  may contain any lower case characters and numbers,
  30091. X          as well as the following special sequences:
  30092. X
  30093. X            %m: Numeric month (01 - 12)
  30094. X
  30095. X            %d: Numeric day of the month (01 - 31)
  30096. X
  30097. X            %y: Year (00 - 99)
  30098. X
  30099. X            %j: Julian date (001 - 366)
  30100. X
  30101. X            %h: Month name (Jan - Dec)
  30102. X
  30103. X            %a: Contents of the  Archive-Name:  header  line,  if
  30104. X            present;  cannot  be  used  if archiving digests. The
  30105. X            Archive-Name: header line has to be manually inserted
  30106. X            by  the  sender of the message; it may show up in the
  30107. X            body of the message as well.
  30108. X
  30109. X            %#: Digest number; can only be used if archiving dig-
  30110. X            ests.
  30111. X
  30112. X            %1: First word of the first  non-blank  line  of  the
  30113. X            message.
  30114. X
  30115. X            %v: Volume number, if the message contains a  'Volume
  30116. X            # Number #' line before the actual message.
  30117. X
  30118. X            %n: Issue number, if the message contains a 'Volume #
  30119. X
  30120. X
  30121. X
  30122. XKubota Computer                                                 7
  30123. X
  30124. X
  30125. X
  30126. X
  30127. X
  30128. X
  30129. Xserver(1)                USER COMMANDS                  server(1)
  30130. X
  30131. X
  30132. X
  30133. X            Number #' line before the actual message.
  30134. X
  30135. X            %%: The character %
  30136. X
  30137. X          For example, to archive messages daily:
  30138. X
  30139. X          archive ermis HOMEDIR/archives/lists/ermis %y%m%d listproc/lists/ermis
  30140. X
  30141. X          or to archive only files sent to the list:
  30142. X
  30143. X          archive venus /ftp/lists/venus vol-%v.num-%n listproc/lists/venus johny-be-good
  30144. X
  30145. X          and in this case the sender that wants  a  file  to  be
  30146. X          archived would precede it with a line similar to:
  30147. X
  30148. X          Volume 10 Number 5
  30149. X
  30150. X          followed by the actual file.
  30151. X
  30152. X          When a new archive file is created, the  Subject:  line
  30153. X          is  used  as  the  short  descriptive  message  for the
  30154. X          archive.
  30155. X
  30156. X     _f_r_e_q_u_e_n_c_y seconds
  30157. X          How often should _s_e_r_v_e_r_d(1) check for  new  mail.  When
  30158. X          _s_e_c_o_n_d_s is set to zero, _s_e_r_v_e_r_d does not sleep.
  30159. X
  30160. X     _b_a_t_c_h start stop
  30161. X          Specify the hours (in military time) when requests  are
  30162. X          to  be  batched.   The defaults are 8 and 20. _s_t_a_r_t and
  30163. X          _s_t_o_p should be within the same day (e.g. 8 am and 1  am
  30164. X          the following day are not valid).
  30165. X
  30166. X     _l_i_m_i_t keyword arguments
  30167. X          Used to set certain limits in the system;  _k_e_y_w_o_r_d  can
  30168. X          be:
  30169. X
  30170. X            _m_e_s_s_a_g_e: limit the size of distributed messages to  a
  30171. X            certain  number  of bytes, which is the _a_r_g_u_m_e_n_t fol-
  30172. X            lowing this keyword.  A notification is sent back  to
  30173. X            the sender when this limit is exceeded, including the
  30174. X            first few  lines  of  his/her  original  message  for
  30175. X            reference.
  30176. X
  30177. X            _f_i_l_e_s: limit the size of archive files  that  can  be
  30178. X            sent  out  to a certain number of bytes, which is the
  30179. X            _a_r_g_u_m_e_n_t following this keyword.  When this limit  is
  30180. X            reached,  the  file  is automatically split into sub-
  30181. X            parts.
  30182. X
  30183. X     _p_r_e_c_e_d_e_n_c_e string
  30184. X          The  header  of  each  outgoing  message   contains   a
  30185. X
  30186. X
  30187. X
  30188. XKubota Computer                                                 8
  30189. X
  30190. X
  30191. X
  30192. X
  30193. X
  30194. X
  30195. Xserver(1)                USER COMMANDS                  server(1)
  30196. X
  30197. X
  30198. X
  30199. X          Precedence: line; _s_t_r_i_n_g can be:
  30200. X
  30201. X            bulk, junk, first-class,  none:  primarily  used  for
  30202. X            vacation programs.
  30203. X
  30204. X     _o_p_t_i_o_n keyword
  30205. X          This defines a series of system-dependent options; _k_e_y_-
  30206. X          _w_o_r_d can be:
  30207. X
  30208. X            _s_y_s_v__p_s: the system will assume a System V version of
  30209. X            ps(1).
  30210. X
  30211. X            _b_s_d__p_s: the system  will  assume  a  BSD  version  of
  30212. X            ps(1).
  30213. X
  30214. X            _b_s_d__m_a_i_l: define it if BSD (UCB) mail is available on
  30215. X            your  system;  if  this  is  the case, make sure that
  30216. X            /usr/ucb/mail is the path (or a link) to it; also see
  30217. X            src/Makefile.   This is used to notify the _m_a_n_a_g_e_r of
  30218. X            any error conditions.
  30219. X
  30220. X            _b_a_d__t_e_l_n_e_t: if the mail method used  (see  below)  is
  30221. X            _t_e_l_n_e_t and the system seems to send out only one mes-
  30222. X            sage and then go to sleep, use this option.
  30223. X
  30224. X            _p_o_s_t__m_a_i_l: this will force the system  to  post  mes-
  30225. X            sages to news groups (using _i_n_e_w_s), using the groups'
  30226. X            names (e.g. misc.test). Make sure that _i_n_e_w_s  resides
  30227. X            in /usr/lib/news, or /usr/lib/news/inews is a link to
  30228. X            it (also see src/Makefile).
  30229. X
  30230. X            _g_a_t_e__m_a_i_l: this will force the system  to  gate  mes-
  30231. X            sages to news, using the gateways' email addresses.
  30232. X
  30233. X            _i_g_n_o_r_e__i_n_v_a_l_i_d__r_e_q_u_e_s_t_s: ignore all unrecognized user
  30234. X            requests and process valid ones only; by default, the
  30235. X            system aborts  processing  requests  upon  the  first
  30236. X            invalid  one,  in  which  case a reply is sent to the
  30237. X            user and all subsequent requests are flushed.
  30238. X
  30239. X            _r_e_l_a_x_e_d__s_y_n_t_a_x: by default, the system complains when
  30240. X            a request is given more arguments than expected. This
  30241. X            turns such checking off.
  30242. X
  30243. X     _m_a_i_l_m_e_t_h_o_d method [arguments]
  30244. X          Every outgoing message should begin with a line of  the
  30245. X          form:
  30246. X
  30247. X            From listproc@your-domain
  30248. X
  30249. X            or
  30250. X
  30251. X
  30252. X
  30253. X
  30254. XKubota Computer                                                 9
  30255. X
  30256. X
  30257. X
  30258. X
  30259. X
  30260. X
  30261. Xserver(1)                USER COMMANDS                  server(1)
  30262. X
  30263. X
  30264. X
  30265. X            From list_alias@your-domain
  30266. X
  30267. X          which depends on the mail _m_e_t_h_o_d used:
  30268. X
  30269. X            _s_y_s_t_e_m: the recommended method; it provides a unified
  30270. X            approach  to  sending mail and it has been ported and
  30271. X            tested  on  lots  of   systems   (see   the   section
  30272. X            PORT SPECIFIC  below).  In addition, since a full set
  30273. X            of the SMTP protocol is implemented, _m_a_n_a_g_e_r and list
  30274. X            owners  will  be  notified  of  invalid addresses and
  30275. X            various system  problems.   Moreover,  mail  will  be
  30276. X            queued  when it cannot be delivered, in the directory
  30277. X            HOMEDIR/mqueue; see _q_u_e_u_e(_1) for more information  on
  30278. X            how to process the mail queue.
  30279. X
  30280. X            This method requires host TCP/IP  and  internet  sup-
  30281. X            port;  consult  the src/README file for more informa-
  30282. X            tion.
  30283. X
  30284. X            _t_e_l_n_e_t: to be used only when _s_y_s_t_e_m is  inappropriate
  30285. X            and telnet(1) is available on your host.
  30286. X
  30287. X            _e_n_v__v_a_r: usually followed by _L_O_G_N_A_M_E  /_b_i_n/_r_m_a_i_l,  or
  30288. X            _L_O_G_N_A_M_E  /_u_s_r/_l_i_b/_s_e_n_d_m_a_i_l  -_b_a (-ba is mandatory) --
  30289. X            to be used only when the previous methods  are  inap-
  30290. X            propriate.
  30291. X
  30292. XMMMMAAAAIIIILLLL LLLLOOOOOOOOPPPPSSSS
  30293. X     The system uses the following  protocol  for  avoiding  mail
  30294. X     loops  between a list and news connections: In the header of
  30295. X     the outgoing message an "Originator: " field is  added.  For
  30296. X     each  list  plus  listproc,  a  log of the most recent (500)
  30297. X     Message-Id's is kept.  Whenever a message is  received,  the
  30298. X     Originator, Reply-To and Message-Id fields are extracted and
  30299. X     looked up in the ".ignored" and ".message.ids" files in  the
  30300. X     list's  subdirectory.  Gateways  that  feed back to the list
  30301. X     should preserve at least the Reply-To and Message-Id fields.
  30302. X     The  Originator  and Message-Id fields are preserved by this
  30303. X     system. A new Reply-To is tacked on when redistributing mail
  30304. X     locally from a peer or a news feed.
  30305. X
  30306. X     To avoid mail loops when forwarding  ListProcessor  requests
  30307. X     to  peers,  the  system looks up the Message-Id field in the
  30308. X     ".message.ids" file  in  HOMEDIR.   If  this  field  is  not
  30309. X     preserved  by  the  peer ListProcessor, it is suggested that
  30310. X     you turn off request forwarding when connecting  with  peers
  30311. X     served  by  such systems, until a unified approach is taken.
  30312. X     The Message-Id field is  preserved  by  this  ListProcessor.
  30313. X     This  system  is also using a special Subject field, totally
  30314. X     proprietary and non-standard, in order to avoid  unnecessary
  30315. X     forwarding of requests, thus cutting down on email traffic.
  30316. X
  30317. X
  30318. X
  30319. X
  30320. XKubota Computer                                                10
  30321. X
  30322. X
  30323. X
  30324. X
  30325. X
  30326. X
  30327. Xserver(1)                USER COMMANDS                  server(1)
  30328. X
  30329. X
  30330. X
  30331. X     In addition,  the  system  searches  incoming  messages  for
  30332. X     Message-Ids in the message body, as well as the occurence of
  30333. X     the X-Listprocessor-Version header line in  it,  since  most
  30334. X     bounced messages include the entire original message.
  30335. X
  30336. X     Finally, a checksum for each incoming  message  is  obtained
  30337. X     and looked up against a database of the 500 most recent sums
  30338. X     in the file ".sums" in the list's subdirectory.
  30339. X
  30340. XCCCCRRRRAAAASSSSHHHH RRRREEEECCCCOOOOVVVVEEEERRRRYYYY
  30341. X     It is possible that a message delivery was interrupted by  a
  30342. X     user (_s_t_a_r_t -_k), or by the system (crash/reboot). A built-in
  30343. X     mechanism guarrantees to pick up delivery again  from  where
  30344. X     it left off, if the system is restarted using _s_t_a_r_t(1). Both
  30345. X     _s_t_a_r_t(1) and _l_i_s_t(1) report to the effect that mail delivery
  30346. X     was interrupted and will resume. On the other hand, process-
  30347. X     ing of interrupted requests will not resume and  all  unpro-
  30348. X     cessed requests will be lost.
  30349. X
  30350. XCCCCOOOOMMMMMMMMUUUUNNNNIIIICCCCAAAATTTTIIIINNNNGGGG
  30351. X     Users send requests to _l_i_s_t_p_r_o_c@_y_o_u_r-_d_o_m_a_i_n and public  mes-
  30352. X     sages to the various _l_i_s_t__a_l_i_a_s@_y_o_u_r-_d_o_m_a_i_n.
  30353. X
  30354. XAAAARRRRCCCCHHHHIIIIVVVVEEEESSSS
  30355. X     The server has an archiving capability  of  files.  Archives
  30356. X     may  be  public  so  that anyone can get files from them, or
  30357. X     private so that only privileged users may obtain files  from
  30358. X     them. There is a master archive in HOMEDIR/archives/listproc
  30359. X     where all subarchives are defined. The archives  keep  lists
  30360. X     of  files that are available to users via a _g_e_t request, and
  30361. X     index of subarchives that are  available  to  users  via  an
  30362. X     _i_n_d_e_x request.
  30363. X
  30364. X     As outlined in _l_i_s_t(1),  each  list's  public  messages  are
  30365. X     automatically  saved  under  the  list's subdirectory in the
  30366. X     file _a_r_c_h_i_v_e.  This file may periodically be placed  in  the
  30367. X     system's  archives  by  hand (if not archiving automatically
  30368. X     via the _a_r_c_h_i_v_e directive), or may point to  /dev/null.  The
  30369. X     archived  files  may  not  necessarily reside in the archive
  30370. X     directories, as long as the archives  know  where  they  are
  30371. X     located. See the man page for _f_a_r_c_h(_1) for more information.
  30372. X
  30373. X     Alternatively, messages may be  automatically  archived  via
  30374. X     the _a_r_c_h_i_v_e directive in the _c_o_n_f_i_g file.
  30375. X
  30376. XHHHHEEEELLLLPPPP
  30377. X     The system comes configured with  default  help  topics  the
  30378. X     recognized requests. More topics may be added by editing the
  30379. X     file  HOMEDIR/help/TOPICS,  adding  the  topic(s)  and   the
  30380. X     file(s) where the actual text exists.
  30381. X
  30382. X
  30383. X
  30384. X
  30385. X
  30386. XKubota Computer                                                11
  30387. X
  30388. X
  30389. X
  30390. X
  30391. X
  30392. X
  30393. Xserver(1)                USER COMMANDS                  server(1)
  30394. X
  30395. X
  30396. X
  30397. X     Help files may be simple text files  or  shell  scripts,  in
  30398. X     which  case  they  have to start with "#!" in the first line
  30399. X     and be followed by the path to the shell  to  be  used;  for
  30400. X     example: #!/bin/sh
  30401. X
  30402. XSSSSYYYYSSSSTTTTEEEEMMMM MMMMAAAAIIIINNNNTTTTEEEENNNNAAAANNNNCCCCEEEE
  30403. X     As mentioned below, all programs report  to  certain  files.
  30404. X     The  system's  manager  should  periodically check the files
  30405. X     HOMEDIR/.report.server        and        the         various
  30406. X     HOMEDIR/lists/*/.report.list for any problems.  All messages
  30407. X     sent are saved under HOMEDIR/mbox  and  HOMEDIR/lists/*/mbox
  30408. X     and  they  should be cleaned up periodically.  For debugging
  30409. X     purposes, various warnings are written to  HOMEDIR/.warning;
  30410. X     this  file,  as  well  as HOMEDIR/.report.catmail are shrunk
  30411. X     every time _s_t_a_r_t(1) is run.
  30412. X
  30413. X     For whenever the necessity arises to administer  the  system
  30414. X     remotely,  the following scheme may be used to start or kill
  30415. X     the system, process the mail queue, force an application  to
  30416. X     execute immediately, etc: a mail message is sent to an alias
  30417. X     whose sole role is to fire up an application;  the  applica-
  30418. X     tion has to have been setuid before.
  30419. X
  30420. X     For instance, to start the system remotely, you may  set  up
  30421. X     an alias such as:
  30422. X
  30423. X       start-server: "|HOMEDIR/start -cr > /dev/null"
  30424. X
  30425. X     To kill the system, you may define another alias:
  30426. X
  30427. X       kill-server: "|HOMEDIR/start -crk > /dev/null"
  30428. X
  30429. X     To force requests to get processed now:
  30430. X
  30431. X       run-listproc: "|HOMEDIR/listproc -1 > /dev/null"
  30432. X
  30433. X     To start the queue daemon:
  30434. X
  30435. X       proc-queue: "|HOMEDIR/queued 60 & > /dev/null"
  30436. X
  30437. X     These aliases should be hard to guess for  obvious  reasons.
  30438. X     The actual message sent to such an alias is discarded.
  30439. X
  30440. XEEEEXXXXIIIITTTT CCCCOOOODDDDEEEESSSS
  30441. X     All applications except tlock use the following  exit  codes
  30442. X     for communication:
  30443. X
  30444. X
  30445. X     0    - OK, normal exit
  30446. X
  30447. X     1    - Could not open or lock file
  30448. X
  30449. X
  30450. X
  30451. X
  30452. XKubota Computer                                                12
  30453. X
  30454. X
  30455. X
  30456. X
  30457. X
  30458. X
  30459. Xserver(1)                USER COMMANDS                  server(1)
  30460. X
  30461. X
  30462. X
  30463. X     2    - SIGINT signal (normal termination)
  30464. X
  30465. X     3    - Command line option error
  30466. X
  30467. X     4    - Syntax error in file
  30468. X
  30469. X     5    - Could not spawn (restart failed)
  30470. X
  30471. X     6    - Shutdown request
  30472. X
  30473. X     7    - Restart request
  30474. X
  30475. X     8    - Received system  signal  (anything  but  SIGINT  will
  30476. X          bring the system down)
  30477. X
  30478. X     9    - Too many multiple recipients
  30479. X
  30480. X     10   - Could not deliver mail (unexpected reply  during  the
  30481. X          SMTP transaction)
  30482. X
  30483. X     11   - malloc() failed
  30484. X
  30485. X     12   - Cannot fork()
  30486. X
  30487. X     13   - Socket connection problem
  30488. X
  30489. X     14   - Semaphore error
  30490. X
  30491. X     15   - Cannot setuid()/setgid()
  30492. X
  30493. X     16   - Internal error or system call failure
  30494. X
  30495. X     tlock exits with:
  30496. X
  30497. X     -1   - File locking not functional
  30498. X
  30499. X     0    - No files locked
  30500. X
  30501. X     1    - Cannot open config
  30502. X
  30503. X     2 & up
  30504. X          - Number of files locked + 1
  30505. X
  30506. XRRRREEEEPPPPOOOORRRRTTTTSSSS
  30507. X     The system provides two ways of reporting progress: via sys-
  30508. X     log(3)  when available (by compiling with -DSYSLOG=facility)
  30509. X     with priority LOG_INFO and facility as specified, or through
  30510. X     its own report files (when not using syslog(3)); these are:
  30511. X
  30512. X     HOMEDIR/.report.catmail
  30513. X          Messages from _c_a_t_m_a_i_l(1) every time  new  messages  are
  30514. X          appended to the various mail files.
  30515. X
  30516. X
  30517. X
  30518. XKubota Computer                                                13
  30519. X
  30520. X
  30521. X
  30522. X
  30523. X
  30524. X
  30525. Xserver(1)                USER COMMANDS                  server(1)
  30526. X
  30527. X
  30528. X
  30529. X     HOMEDIR/.report.daemon
  30530. X          Messages  from  _s_e_r_v_e_r_d(1)  every  time  new  mail  has
  30531. X          arrived.
  30532. X
  30533. X     HOMEDIR/.report.list
  30534. X          Error messages from _l_i_s_t(1) when attempting to  process
  30535. X          public messages.
  30536. X
  30537. X     HOMEDIR/.report.pqueue
  30538. X          Messages from _p_q_u_e_u_e (see _q_u_e_u_e(1)).
  30539. X
  30540. X     HOMEDIR/.report.server
  30541. X          Messages from _l_i_s_t_p_r_o_c(1) every time new  requests  are
  30542. X          processed.
  30543. X
  30544. X     HOMEDIR/.report.start
  30545. X          Generated by _s_t_a_r_t(1) every time the system is started.
  30546. X
  30547. X     HOMEDIR/lists/LIST_ALIAS/.report.list
  30548. X          Messages from _l_i_s_t(1) when processing public messages.
  30549. X
  30550. X     HOMEDIR/.*.acc
  30551. X          Accumulated  reports  since  the   system   was   first
  30552. X          installed.
  30553. X
  30554. X     HOMEDIR/lists/*/.*.acc
  30555. X          Accumulated reports for each mailing list.
  30556. X
  30557. X     Every report includes a time stamp; every  list  and  server
  30558. X     report  also  includes the actual sender of the message, and
  30559. X     every server  report  includes  all  requests  made  by  the
  30560. X     sender.
  30561. X
  30562. X     Whenever a program dies abnormally (and BSD mail is present)
  30563. X     a  message  is  sent  to _m_a_n_a_g_e_r (as defined in _c_o_n_f_i_g). The
  30564. X     message is usually sent by _s_e_r_v_e_r_d(1) which then exits.  The
  30565. X     daemon  dies  with a different message according to the exit
  30566. X     status of the child; the various error conditions  that  may
  30567. X     occur are:
  30568. X
  30569. X     Could not open file
  30570. X          HOMEDIR is not a  valid  path;  file  was  accidentally
  30571. X          deleted;  insufficient access privileges. Run _s_e_t_u_p and
  30572. X          _s_t_a_r_t.
  30573. X
  30574. X     Could not lock file
  30575. X          HOMEDIR is not a  valid  path;  file  was  accidentally
  30576. X          deleted;  insufficient  access privileges; another pro-
  30577. X          gram is using the lock file. Run _t_l_o_c_k, and  if  neces-
  30578. X          sary,  _u_l_o_c_k;  then  _s_t_a_r_t.   _t_l_o_c_k  checks  for locked
  30579. X          files, and _u_l_o_c_k removes all lock files.
  30580. X
  30581. X
  30582. X
  30583. X
  30584. XKubota Computer                                                14
  30585. X
  30586. X
  30587. X
  30588. X
  30589. X
  30590. X
  30591. Xserver(1)                USER COMMANDS                  server(1)
  30592. X
  30593. X
  30594. X
  30595. X     Command line option error
  30596. X          Check the _c_o_n_f_i_g file and restart.
  30597. X
  30598. X     Syntax error in file
  30599. X          Check _c_o_n_f_i_g, all  reports,  .subscribers,  .peers  and
  30600. X          .news files.
  30601. X
  30602. X     Could not spawn
  30603. X          No more processes.
  30604. X
  30605. X     Received system signal
  30606. X          SIGQUIT, SIGTERM, SIGBUS, SIGSEGV, SIGILL.
  30607. X
  30608. XFFFFIIIILLLLEEEESSSS
  30609. X     HOMEDIR/.aliases
  30610. X          Aliases of email addresses of users having trouble get-
  30611. X          ting replies to requests.
  30612. X
  30613. X     HOMEDIR/.awk
  30614. X          awk program for formatting the _s_t_a_t_i_s_t_i_c_s request.
  30615. X
  30616. X     HOMEDIR/.grep
  30617. X          script used for counting the number of messages sent by
  30618. X          a subscriber.
  30619. X
  30620. X     HOMEDIR/.ignored
  30621. X          List of unwanted senders.
  30622. X
  30623. X     HOMEDIR/.lock.pqueue
  30624. X          Lock file for _p_q_u_e_u_e (see _q_u_e_u_e(1)).
  30625. X
  30626. X     HOMEDIR/.lock.serverd
  30627. X          Lock file for _s_e_r_v_e_r_d(1).
  30628. X
  30629. X     HOMEDIR/.message.ids
  30630. X          A database of recent message id's used to  detect  mail
  30631. X          loops.
  30632. X
  30633. X     HOMEDIR/.queue.id
  30634. X          Next id to be assigned to  next  undeliverable  message
  30635. X          placed in the mqueue/ directory.
  30636. X
  30637. X     HOMEDIR/.reply.listser
  30638. X          The reply code given to _s_e_r_v_e_r_d(1) during a  live  ses-
  30639. X          sion.
  30640. X
  30641. X     HOMEDIR/.rep.server.acc
  30642. X          Archived _l_i_s_t_p_r_o_c(1) reports.
  30643. X
  30644. X     HOMEDIR/.rep.serverd.acc
  30645. X          Archived _s_e_r_v_e_r_d(1) reports.
  30646. X
  30647. X
  30648. X
  30649. X
  30650. XKubota Computer                                                15
  30651. X
  30652. X
  30653. X
  30654. X
  30655. X
  30656. X
  30657. Xserver(1)                USER COMMANDS                  server(1)
  30658. X
  30659. X
  30660. X
  30661. X     HOMEDIR/.rep.start.acc
  30662. X          Archived _s_t_a_r_t(1) reports.
  30663. X
  30664. X     HOMEDIR/.report.catmail
  30665. X          Current _c_a_t_m_a_i_l(1) report.
  30666. X
  30667. X     HOMEDIR/.report.daemon
  30668. X          Current _s_e_r_v_e_r_d(1) report.
  30669. X
  30670. X     HOMEDIR/.report.list
  30671. X